首页 > 解决方案 > 无法在 V8 C++ 嵌入中重新运行已编译的脚本

问题描述

我试图在给定的上下文/范围内重新运行 V8 脚本,但我遇到了分段错误。如果我编译其他脚本并连续运行它就可以了。

int loadScript(const char * scriptCode) {
  v8::Local<v8::String> source =
    v8::String::NewFromUtf8(isolate, scriptCode,
    v8::NewStringType::kNormal)
    .ToLocalChecked();

  // Compile the source code.
  script =
    v8::Script::Compile(context, source).ToLocalChecked();

  return 0;
}

std::string executeScript() {
  // Run the script to get the result.
  v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

  // Convert the result to an UTF8 string and print it.
  v8::String::Utf8Value utf8(isolate, result);

  return std::string(*utf8);
}

////

sv8i.loadScript("let a = 1; \
    let b = 2; \
    JSON.stringify({a, b}); \
  ");

  printf("%s\n", sv8i.executeScript().c_str());
  printf("%s\n", sv8i.executeScript().c_str());  // Seg fault

结果是:

    {"a":1,"b":2}
Thread 1 "spirit_v8_test" received signal SIGSEGV, Segmentation fault.
    0x000055555585c9c8 in v8::internal::ScriptContextTable::Lookup(v8::internal::Isolate*, v8::internal::ScriptContextTable, v8::internal::String, v8::internal::VariableLookupResult*) ()
    (gdb) backtrace
    #0  0x000055555585c9c8 in v8::internal::ScriptContextTable::Lookup(v8::internal::Isolate*, v8::internal::ScriptContextTable, v8::internal::String, v8::internal::VariableLookupResult*) ()
    #1  0x00005555556e3cfc in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) ()
    #2  0x00005555556e36a6 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*) ()
    #3  0x0000555555651990 in v8::Script::Run(v8::Local<v8::Context>) ()
    #4  0x00005555556444b9 in SpiritV8Interface::executeScript[abi:cxx11]() (this=0x7fffffffe2b0) at ./spirit_bin_src/spirit_v8_interface.cpp:54
    #5  0x00005555556446a9 in main (argc=1, argv=0x7fffffffe4a8) at ./spirit_bin_src/spirit_v8_interface.cpp:80

为什么?

标签: javascriptc++v8

解决方案


(1) 欢迎来到 StackOverflow!请注意,StackOverflow 不是“请为我调试代码”服务。从这个意义上说,有人可能会争辩说这个问题应该结束。

也就是说,这里还有一些可以说的东西,并且更普遍适用:

(2) 如果您确实需要一段代码的帮助,请发布一个完整的、可重现的示例
在手头的案例中,缺少一些关键信息,这可以很好地解释出了什么问题:scriptand的类型是context什么?它们何时以及如何初始化?他们的寿命是多少?它们v8::Local是 s,如果是,管理它们的 HandleScopes 在哪里?我敢打赌,问题出在这个领域的某个地方,但是除非您发布整个代码(足够完整,如果我愿意,我可以复制粘贴它并在本地运行它),否则很难确定。

(3)一旦你越过了segfault,你会遇到另一个问题:.ToLocalChecked()意思是“我知道这MaybeLocal不是空的,如果我错了它实际上的,那么我希望进程崩溃。JavaScript 是一种非常适合异常处理的语言,因此作为 C++ 嵌入器,您必须处理几乎任何 JS 代码都可能抛出的可能性。这就是MaybeLocals 的用途:您可以检查它们是否包含值,或者异常是否阻止了结果值的返回。您还可以使用 av8::TryCatch来捕获引发的异常,从而导致空MaybeLocal.
更改 JavaScript 片段使其工作的事实在这里是一个很大的提示:运行let a = 1在同一上下文中两次当然会抛出异常。如果你用 来“处理”它.ToLocalChecked(),那么你就是在要求崩溃。

阅读 V8 的嵌入器文档可能会有所帮助,该文档更详细地解释了这些以及许多其他概念。(当您使用它时,也许还有一些 StackOverflow 介绍性文档。)


推荐阅读