Reputation: 1
I've been trying to embed V8 javascript engine to my project. For the most part this has been successful, but there is one problem that doesn't seem to go away and I don't know what causes it.
When I write even a simple for loop to iterate array of few thousand entries, V8 segfaults. Valgrind says this:
==38120== Invalid read of size 8
==38120== at 0x525F654: v8::internal::Isolate::main_thread_local_heap() (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x53A532A: v8::internal::interpreter::BytecodeArrayIterator::BytecodeArrayIterator(v8::internal::Handle<v8::internal::BytecodeArray>, int) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5C01534: v8::internal::baseline::BaselineCompiler::BaselineCompiler(v8::internal::LocalIsolate*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Handle<v8::internal::BytecodeArray>) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5C143E9: v8::internal::GenerateBaselineCode(v8::internal::Isolate*, v8::internal::Handle<v8::internal::SharedFunctionInfo>) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x51D796E: v8::internal::Compiler::CompileSharedWithBaseline(v8::internal::Isolate*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Compiler::ClearExceptionFlag, v8::internal::IsCompiledScope*) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x51D7CF5: v8::internal::Compiler::CompileBaseline(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Compiler::ClearExceptionFlag, v8::internal::IsCompiledScope*) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5BFF355: v8::internal::baseline::BaselineBatchCompiler::CompileBatch(v8::internal::Handle<v8::internal::JSFunction>) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5BFEF8E: v8::internal::baseline::BaselineBatchCompiler::EnqueueFunction(v8::internal::Handle<v8::internal::JSFunction>) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5276501: v8::internal::TieringManager::OnInterruptTick(v8::internal::Handle<v8::internal::JSFunction>) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5D8BA69: v8::internal::Runtime_BytecodeBudgetInterruptWithStackCheck(int, unsigned long*, v8::internal::Isolate*) (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5AEA9F7: Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit (in /home/ktp/oma/lib/liboma_js.so)
==38120== by 0x5B98E62: Builtins_JumpLoopHandler (in /home/ktp/oma/lib/liboma_js.so)
==38120== Address 0xf100 is not stack'd, malloc'd or (recently) free'd
My bindings and setup is pretty much based on the examples from v8.dev's guide to embedding, although wrapped in a class and with v8::platform::PumpMessageLoop() called with timerfd in epoll loop which runs in same thread as V8.
The JS code that caused valgrind message was this:
var g = new Array(1024*16);
g.fill(0);
for(var i in g)
{
i+i;
}
The JS code works when array's size is at max 1024*7 and when I printed the iteration count, it crashed at around 7500.
Edit: this C++ code gives the same error and is pretty much shortened version of the code I am using:
#include <v8.h>
#include <v8-context.h>
#include <v8-isolate.h>
#include <v8-local-handle.h>
#include <v8-primitive.h>
#include <v8-script.h>
#include <v8-json.h>
#include <libplatform/libplatform.h>
int main(int argc, char *argv[])
{
// Initialize V8.
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// Create a new Isolate and make it the current one.
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
std::string src = R"(
for(var i=0;i<1024*8;i++)
{
}
)";
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> ctx = v8::Context::New(isolate);
v8::Context::Scope context_scope(ctx);
v8::MaybeLocal<v8::String> vsrc = v8::String::NewFromUtf8(isolate, src.c_str(), v8::NewStringType::kNormal, static_cast<int>(src.size()));
v8::MaybeLocal<v8::Script> script = v8::Script::Compile(ctx, vsrc.ToLocalChecked()).ToLocalChecked();
if(script.IsEmpty())
{
printf("error0\n");
}
v8::MaybeLocal<v8::Value> result = script.ToLocalChecked()->Run(ctx);
if(result.IsEmpty())
{
printf("error1\n");
}
}
isolate->Dispose();
v8::V8::Dispose();
v8::V8::DisposePlatform();
delete create_params.array_buffer_allocator;
return 0;
}
Example was compiled with these commands:
g++ -c /home/ktp/oma/src/jx.cpp -DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX -I/home/ktp/v8/v8/include/ -fPIC -Wall -g -std=c++17
g++ -o /home/ktp/oma/bin/jx jx.o -DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX -lv8_monolith -ldl -lpthread -L/home/ktp/v8/v8/out.gn/x64.release.sample/obj/
I am not entirely sure about V8 version, but I built it on 30.8. and d8 console says V8 version 10.7.0.
V8 was built according to the instructions at v8.dev and https://v8.dev/docs/source-code#using-git :
tools/dev/v8gen.py x64.release.sample
ninja -C out.gn/x64.release.sample v8_monolith
gn args says this:
dcheck_always_on = false
is_component_build = false
is_debug = false
target_cpu = "x64"
use_custom_libcxx = false
v8_enable_sandbox = true
v8_monolithic = true
v8_use_external_startup_data = false
Upvotes: 0
Views: 399
Reputation: 40561
You need to enter the Isolate
. You can either use isolate->Enter()
and isolate->Exit()
, or a v8::Isolate::Scope isolate_scope(isolate)
(which is a convenience wrapper around those two steps), somewhere between creating the Isolate and creating the HandleScope.
To help you help yourself:
gn args out/x64.release.sample
) to say is_debug = true
to get a Debug build, and recompile.gdb -args /home/ktp/oma/bin/jx
(or whichever debugger you prefer to use).Debug check failed: (isolate) != nullptr
. If you request a backtrace, you'll see that this happens somewhere deep in V8's guts; luckily the specifics don't matter in this case.Isolate::Scope
stands out as a likely suspect.Upvotes: 1