diff --git a/API/hermes/hermes.cpp b/API/hermes/hermes.cpp index f7d4791c306..406c3c1a1b2 100644 --- a/API/hermes/hermes.cpp +++ b/API/hermes/hermes.cpp @@ -1197,15 +1197,25 @@ void HermesRuntime::setFatalHandler(void (*handler)(const std::string &)) { } namespace { -// A class which adapts a jsi buffer to a Hermes buffer. + +/// A class which adapts a jsi buffer to a Hermes buffer. +/// It also provides the ability to create a partial "view" into the buffer. class BufferAdapter final : public ::hermes::Buffer { public: - BufferAdapter(std::shared_ptr buf) : buf_(std::move(buf)) { - data_ = buf_->data(); - size_ = buf_->size(); + explicit BufferAdapter( + const std::shared_ptr &buf, + const uint8_t *data, + size_t size) + : buf_(buf) { + data_ = data; + size_ = size; } + explicit BufferAdapter(const std::shared_ptr &buf) + : BufferAdapter(buf, buf->data(), buf->size()) {} + private: + /// The buffer we are "adapting". std::shared_ptr buf_; }; } // namespace @@ -1420,6 +1430,28 @@ class HermesPreparedJavaScript final : public jsi::PreparedJavaScript { } }; +#ifndef HERMESVM_LEAN + +/// If the buffer contains an embedded terminating zero, shrink it, so it is +/// one past the size, as per the LLVM MemoryBuffer convention. Otherwise, copy +/// it into a new zero-terminated buffer. +std::unique_ptr ensureZeroTerminated( + const std::shared_ptr &buf) { + size_t size = buf->size(); + const uint8_t *data = buf->data(); + + // Check for zero termination + if (size != 0 && data[size - 1] == 0) { + return std::make_unique(buf, data, size - 1); + } else { + // Copy into a zero-terminated instance. + return std::make_unique(std::make_shared( + std::string((const char *)data, size))); + } +} + +#endif + } // namespace std::shared_ptr @@ -1428,11 +1460,10 @@ HermesRuntimeImpl::prepareJavaScriptWithSourceMap( const std::shared_ptr &sourceMapBuf, std::string sourceURL) { std::pair, std::string> bcErr{}; - auto buffer = std::make_unique(jsiBuffer); vm::RuntimeModuleFlags runtimeFlags{}; runtimeFlags.persistent = true; - bool isBytecode = isHermesBytecode(buffer->data(), buffer->size()); + bool isBytecode = isHermesBytecode(jsiBuffer->data(), jsiBuffer->size()); #ifdef HERMESVM_PLATFORM_LOGGING hermesLog( "HermesVM", "Prepare JS on %s.", isBytecode ? "bytecode" : "source"); @@ -1444,18 +1475,17 @@ HermesRuntimeImpl::prepareJavaScriptWithSourceMap( throw std::logic_error("Source map cannot be specified with bytecode"); } bcErr = hbc::BCProviderFromBuffer::createBCProviderFromBuffer( - std::move(buffer)); + std::make_unique(jsiBuffer)); } else { #if defined(HERMESVM_LEAN) bcErr.second = "prepareJavaScript source compilation not supported"; #else std::unique_ptr<::hermes::SourceMap> sourceMap{}; if (sourceMapBuf) { + auto buf0 = ensureZeroTerminated(sourceMapBuf); // Convert the buffer into a form the parser needs. llvh::MemoryBufferRef mbref( - llvh::StringRef( - (const char *)sourceMapBuf->data(), sourceMapBuf->size()), - ""); + llvh::StringRef((const char *)buf0->data(), buf0->size()), ""); ::hermes::SimpleDiagHandler diag; ::hermes::SourceErrorManager sm; diag.installInto(sm); @@ -1467,7 +1497,10 @@ HermesRuntimeImpl::prepareJavaScriptWithSourceMap( } } bcErr = hbc::BCProviderFromSrc::createBCProviderFromSrc( - std::move(buffer), sourceURL, std::move(sourceMap), compileFlags_); + ensureZeroTerminated(jsiBuffer), + sourceURL, + std::move(sourceMap), + compileFlags_); #endif } if (!bcErr.first) {