V8,从 C++ 生成和抛出错误对象的正确方法是什么
V8, What is the correct way to generate and throw error objects from C++
我正在将 V8(版本 8.1.307)嵌入到应用程序中。
我正在使用节点 source.com 提供的 API reference,以及 Google 的嵌入指南。
我在尝试做一件看似简单的事情时遇到了障碍:生成错误对象以响应从 Javascript 对 C++ 函数的无效调用。
文档表明它应该像构建 v8::Local <v8::String>
并将其传递给 v8::Exception::RangeError()
或类似函数一样简单,但这会触发 V8 内部的段错误。
我仔细研究了可用的示例,但它们只提供了如何将原始字符串作为异常抛出的演示,如果可能的话我宁愿不这样做。
我是不是遗漏了一些简单的东西,或者这真的坏了还是不受支持?
//Note: ErrorFactory is defined as:
typedef v8::Local <v8::Value>(*ErrorFactory)(v8::Local <v8::String>);
void ScriptManager::ConvertNativeExceptionToJavascriptError(ErrorFactory NewError, std::exception& exception)
{
v8::Local <v8::String> errstr = v8::String::NewFromUtf8(mIsolate, exception.what(), v8::NewStringType::kNormal).ToLocalChecked();
mIsolate->ThrowException(NewError(errstr));
}
后面调用如下:
catch(std::exception& e)
{
//Just pick RangeError for demonstration's sake.
engine->ConvertNativeExceptionToJavascriptError(v8::Exception::RangeError, e);
}
它在 RangeError 调用期间在 V8 内部崩溃:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==7680==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000a058 (pc 0x00010e07c771 bp 0x7ffee1c0baf0 sp 0x7ffee1c0ba90 T0)
==7680==The signal is caused by a READ memory access.
#0 0x10e07c770 in v8::Exception::RangeError(v8::Local<v8::String>) api.cc:9199
#1 0x10dff9904 in ScriptManager::ConvertNativeExceptionToJavascriptError(v8::Local<v8::Value> (*)(v8::Local<v8::String>), std::exception&) javascript.cpp:316
#2 0x10dff7cca in CallFunction(v8::FunctionCallbackInfo<v8::Value> const&) javascript.cpp:66
#3 0x10e0bce80 in v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) api-arguments-inl.h:158
#4 0x10e0bc353 in v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) builtins-api.cc:111
#5 0x10e0bb932 in v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) builtins-api.cc:141
#6 0x10ec9ac38 in Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit (test:x86_64+0x100ca8c38)
#7 0x10ec33452 in Builtins_InterpreterEntryTrampoline (test:x86_64+0x100c41452)
#8 0x10ec310b9 in Builtins_JSEntryTrampoline (test:x86_64+0x100c3f0b9)
#9 0x10ec30e97 in Builtins_JSEntry (test:x86_64+0x100c3ee97)
#10 0x10e180f90 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) execution.cc:372
#11 0x10e180297 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>*) execution.cc:466
#12 0x10e051399 in v8::Script::Run(v8::Local<v8::Context>) api.cc:2158
#13 0x10e004b55 in ScriptContext::ExecuteString(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) javascript.cpp:448
#14 0x10e00572c in ScriptContext::ExecuteFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) javascript.cpp:466
#15 0x10dff3b23 in main test.cpp:28
#16 0x7fff6a527cc8 in start (libdyld.dylib:x86_64+0x1acc8)
==7680==Register values:
rax = 0x0000000000000000 rbx = 0x0000000000000000 rcx = 0x0000000000000000 rdx = 0x0000100000000000
rdi = 0x000062500000c9d0 rsi = 0x00007ffee1c0bb40 rbp = 0x00007ffee1c0baf0 rsp = 0x00007ffee1c0ba90
r8 = 0x000062500000c9d0 r9 = 0xffffebffffff7748 r10 = 0x0000000000000043 r11 = 0x0000000000000060
r12 = 0x000060e000000520 r13 = 0x00007ffee1c0d7e0 r14 = 0x000062500000c9d0 r15 = 0x00001fffdc381afd
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV api.cc:9199 in v8::Exception::RangeError(v8::Local<v8::String>)
==7680==ABORTING
Abort trap: 6
代码看起来不错。我建议您使用 V8 和您的应用程序的调试版本,看看在崩溃之前是否有任何 DCHECK
失败。这些可能会为问题所在提供有价值的见解。
此类崩溃的一个可能原因是“指针压缩”配置不匹配。默认情况下,V8 在最新版本中启用了此功能。如果不更改该默认值,则必须确保编译任何自己的编译单元,#include v8.h with -DV8_COMPRESS_POINTERS -DV8_31BIT_SMIS_ON_64BIT_ARCH
in your C++ compiler flags.
此外,请注意 V8 通常使用 -fno-exceptions
编译。我没有将它与使用 C++ 异常的应用程序链接的经验;所以我不确定这是否会造成任何麻烦。
(任何 v8::String
都可以;无论您使用 NewFromOneByte
还是 NewFromUtf8
构造它只会影响您提供的输入的解码方式,结果 v8::String
将是一样。)
我正在将 V8(版本 8.1.307)嵌入到应用程序中。 我正在使用节点 source.com 提供的 API reference,以及 Google 的嵌入指南。
我在尝试做一件看似简单的事情时遇到了障碍:生成错误对象以响应从 Javascript 对 C++ 函数的无效调用。
文档表明它应该像构建 v8::Local <v8::String>
并将其传递给 v8::Exception::RangeError()
或类似函数一样简单,但这会触发 V8 内部的段错误。
我仔细研究了可用的示例,但它们只提供了如何将原始字符串作为异常抛出的演示,如果可能的话我宁愿不这样做。 我是不是遗漏了一些简单的东西,或者这真的坏了还是不受支持?
//Note: ErrorFactory is defined as:
typedef v8::Local <v8::Value>(*ErrorFactory)(v8::Local <v8::String>);
void ScriptManager::ConvertNativeExceptionToJavascriptError(ErrorFactory NewError, std::exception& exception)
{
v8::Local <v8::String> errstr = v8::String::NewFromUtf8(mIsolate, exception.what(), v8::NewStringType::kNormal).ToLocalChecked();
mIsolate->ThrowException(NewError(errstr));
}
后面调用如下:
catch(std::exception& e)
{
//Just pick RangeError for demonstration's sake.
engine->ConvertNativeExceptionToJavascriptError(v8::Exception::RangeError, e);
}
它在 RangeError 调用期间在 V8 内部崩溃:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==7680==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000a058 (pc 0x00010e07c771 bp 0x7ffee1c0baf0 sp 0x7ffee1c0ba90 T0)
==7680==The signal is caused by a READ memory access.
#0 0x10e07c770 in v8::Exception::RangeError(v8::Local<v8::String>) api.cc:9199
#1 0x10dff9904 in ScriptManager::ConvertNativeExceptionToJavascriptError(v8::Local<v8::Value> (*)(v8::Local<v8::String>), std::exception&) javascript.cpp:316
#2 0x10dff7cca in CallFunction(v8::FunctionCallbackInfo<v8::Value> const&) javascript.cpp:66
#3 0x10e0bce80 in v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) api-arguments-inl.h:158
#4 0x10e0bc353 in v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) builtins-api.cc:111
#5 0x10e0bb932 in v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) builtins-api.cc:141
#6 0x10ec9ac38 in Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit (test:x86_64+0x100ca8c38)
#7 0x10ec33452 in Builtins_InterpreterEntryTrampoline (test:x86_64+0x100c41452)
#8 0x10ec310b9 in Builtins_JSEntryTrampoline (test:x86_64+0x100c3f0b9)
#9 0x10ec30e97 in Builtins_JSEntry (test:x86_64+0x100c3ee97)
#10 0x10e180f90 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) execution.cc:372
#11 0x10e180297 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>*) execution.cc:466
#12 0x10e051399 in v8::Script::Run(v8::Local<v8::Context>) api.cc:2158
#13 0x10e004b55 in ScriptContext::ExecuteString(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) javascript.cpp:448
#14 0x10e00572c in ScriptContext::ExecuteFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) javascript.cpp:466
#15 0x10dff3b23 in main test.cpp:28
#16 0x7fff6a527cc8 in start (libdyld.dylib:x86_64+0x1acc8)
==7680==Register values:
rax = 0x0000000000000000 rbx = 0x0000000000000000 rcx = 0x0000000000000000 rdx = 0x0000100000000000
rdi = 0x000062500000c9d0 rsi = 0x00007ffee1c0bb40 rbp = 0x00007ffee1c0baf0 rsp = 0x00007ffee1c0ba90
r8 = 0x000062500000c9d0 r9 = 0xffffebffffff7748 r10 = 0x0000000000000043 r11 = 0x0000000000000060
r12 = 0x000060e000000520 r13 = 0x00007ffee1c0d7e0 r14 = 0x000062500000c9d0 r15 = 0x00001fffdc381afd
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV api.cc:9199 in v8::Exception::RangeError(v8::Local<v8::String>)
==7680==ABORTING
Abort trap: 6
代码看起来不错。我建议您使用 V8 和您的应用程序的调试版本,看看在崩溃之前是否有任何 DCHECK
失败。这些可能会为问题所在提供有价值的见解。
此类崩溃的一个可能原因是“指针压缩”配置不匹配。默认情况下,V8 在最新版本中启用了此功能。如果不更改该默认值,则必须确保编译任何自己的编译单元,#include v8.h with -DV8_COMPRESS_POINTERS -DV8_31BIT_SMIS_ON_64BIT_ARCH
in your C++ compiler flags.
此外,请注意 V8 通常使用 -fno-exceptions
编译。我没有将它与使用 C++ 异常的应用程序链接的经验;所以我不确定这是否会造成任何麻烦。
(任何 v8::String
都可以;无论您使用 NewFromOneByte
还是 NewFromUtf8
构造它只会影响您提供的输入的解码方式,结果 v8::String
将是一样。)