V8 Segfault when using Global with Value
I am getting started with embedding v8 and I am encountering some 'unexpected behavior'. The following code produces a Segmentation fault (core dumped) when the variable value_ is not Reset at the end (see comment in code). However, the same does not apply for the context context_. Why? This answer seems to be related but does not provide an explanation.
My expectation was that isolate->Dispose() takes care of both.
#include <stdlib.h>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
int main(int argc, char* argv) {
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();
{
// Initialize V8.
// 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);
v8::Global<v8::Context> context_;
v8::Global<v8::String> value_;
{
// Global Context Setup
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
context_.Reset(isolate, context);
// Global Value Setup
v8::Context::Scope context_scope(context);
v8::Local<v8::String> value = v8::String::NewFromUtf8(isolate, "segfault", v8::NewStringType::kNormal).ToLocalChecked();
value_.Reset(isolate, value);
}
// value_.Reset(); // <- Why is this line needed?
// context_.Reset(); // <- Why is this line NOT needed?
isolate->Dispose();
delete create_params.array_buffer_allocator;
}
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
return 0;
}
Build setup:
Follow the instruction in Run the example from the official Getting started with embedding V8. Save the code to sample/wasm.cc and execute following commands:
$ g++ -I. -O2 -Iinclude samples/segfault.cc -o segfault -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17
$ ./segfault
c++ v8 embedded-v8
add a comment |
I am getting started with embedding v8 and I am encountering some 'unexpected behavior'. The following code produces a Segmentation fault (core dumped) when the variable value_ is not Reset at the end (see comment in code). However, the same does not apply for the context context_. Why? This answer seems to be related but does not provide an explanation.
My expectation was that isolate->Dispose() takes care of both.
#include <stdlib.h>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
int main(int argc, char* argv) {
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();
{
// Initialize V8.
// 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);
v8::Global<v8::Context> context_;
v8::Global<v8::String> value_;
{
// Global Context Setup
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
context_.Reset(isolate, context);
// Global Value Setup
v8::Context::Scope context_scope(context);
v8::Local<v8::String> value = v8::String::NewFromUtf8(isolate, "segfault", v8::NewStringType::kNormal).ToLocalChecked();
value_.Reset(isolate, value);
}
// value_.Reset(); // <- Why is this line needed?
// context_.Reset(); // <- Why is this line NOT needed?
isolate->Dispose();
delete create_params.array_buffer_allocator;
}
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
return 0;
}
Build setup:
Follow the instruction in Run the example from the official Getting started with embedding V8. Save the code to sample/wasm.cc and execute following commands:
$ g++ -I. -O2 -Iinclude samples/segfault.cc -o segfault -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17
$ ./segfault
c++ v8 embedded-v8
add a comment |
I am getting started with embedding v8 and I am encountering some 'unexpected behavior'. The following code produces a Segmentation fault (core dumped) when the variable value_ is not Reset at the end (see comment in code). However, the same does not apply for the context context_. Why? This answer seems to be related but does not provide an explanation.
My expectation was that isolate->Dispose() takes care of both.
#include <stdlib.h>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
int main(int argc, char* argv) {
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();
{
// Initialize V8.
// 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);
v8::Global<v8::Context> context_;
v8::Global<v8::String> value_;
{
// Global Context Setup
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
context_.Reset(isolate, context);
// Global Value Setup
v8::Context::Scope context_scope(context);
v8::Local<v8::String> value = v8::String::NewFromUtf8(isolate, "segfault", v8::NewStringType::kNormal).ToLocalChecked();
value_.Reset(isolate, value);
}
// value_.Reset(); // <- Why is this line needed?
// context_.Reset(); // <- Why is this line NOT needed?
isolate->Dispose();
delete create_params.array_buffer_allocator;
}
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
return 0;
}
Build setup:
Follow the instruction in Run the example from the official Getting started with embedding V8. Save the code to sample/wasm.cc and execute following commands:
$ g++ -I. -O2 -Iinclude samples/segfault.cc -o segfault -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17
$ ./segfault
c++ v8 embedded-v8
I am getting started with embedding v8 and I am encountering some 'unexpected behavior'. The following code produces a Segmentation fault (core dumped) when the variable value_ is not Reset at the end (see comment in code). However, the same does not apply for the context context_. Why? This answer seems to be related but does not provide an explanation.
My expectation was that isolate->Dispose() takes care of both.
#include <stdlib.h>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
int main(int argc, char* argv) {
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();
{
// Initialize V8.
// 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);
v8::Global<v8::Context> context_;
v8::Global<v8::String> value_;
{
// Global Context Setup
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
context_.Reset(isolate, context);
// Global Value Setup
v8::Context::Scope context_scope(context);
v8::Local<v8::String> value = v8::String::NewFromUtf8(isolate, "segfault", v8::NewStringType::kNormal).ToLocalChecked();
value_.Reset(isolate, value);
}
// value_.Reset(); // <- Why is this line needed?
// context_.Reset(); // <- Why is this line NOT needed?
isolate->Dispose();
delete create_params.array_buffer_allocator;
}
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
return 0;
}
Build setup:
Follow the instruction in Run the example from the official Getting started with embedding V8. Save the code to sample/wasm.cc and execute following commands:
$ g++ -I. -O2 -Iinclude samples/segfault.cc -o segfault -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17
$ ./segfault
c++ v8 embedded-v8
c++ v8 embedded-v8
edited Dec 30 '18 at 23:55
mhk
asked Dec 30 '18 at 23:20
mhkmhk
254
254
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
v8::Globalhas a destructor that will callReset().The global handles are held in the
Isolate, afterIsolate::Dispose(), the global handles will be freed.
Thus, if you don't call Global::Reset(), but Dispose the Isolate before the destruction of a Global, the destructor of Global will cause a access-after-free, which is a typical Undefined Behavior.
Reset() will set the internal pointer to nullptr, and subsequent call will check this fact and doesn't do anything. That's why you can add a Reset() before Dispose() to avoid the UB.
That's also true for your Global<Context>, it doesn't demonstrate itself because access-after-free doesn't always trigger a segfault.
Is there a reason, whyGlobal::Reset()is not automatically called on all registered global objects whenIsolate::Dispose()is invoked?
– mhk
Dec 31 '18 at 15:10
@mhkGlobalessentially contains a pointer to the storage node.Isolatehas no way to change that pointer value. BecauseIsolatedoesn't know where theGlobalis in user's code.
– llllllllll
Dec 31 '18 at 15:15
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982229%2fv8-segfault-when-using-global-with-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
v8::Globalhas a destructor that will callReset().The global handles are held in the
Isolate, afterIsolate::Dispose(), the global handles will be freed.
Thus, if you don't call Global::Reset(), but Dispose the Isolate before the destruction of a Global, the destructor of Global will cause a access-after-free, which is a typical Undefined Behavior.
Reset() will set the internal pointer to nullptr, and subsequent call will check this fact and doesn't do anything. That's why you can add a Reset() before Dispose() to avoid the UB.
That's also true for your Global<Context>, it doesn't demonstrate itself because access-after-free doesn't always trigger a segfault.
Is there a reason, whyGlobal::Reset()is not automatically called on all registered global objects whenIsolate::Dispose()is invoked?
– mhk
Dec 31 '18 at 15:10
@mhkGlobalessentially contains a pointer to the storage node.Isolatehas no way to change that pointer value. BecauseIsolatedoesn't know where theGlobalis in user's code.
– llllllllll
Dec 31 '18 at 15:15
add a comment |
v8::Globalhas a destructor that will callReset().The global handles are held in the
Isolate, afterIsolate::Dispose(), the global handles will be freed.
Thus, if you don't call Global::Reset(), but Dispose the Isolate before the destruction of a Global, the destructor of Global will cause a access-after-free, which is a typical Undefined Behavior.
Reset() will set the internal pointer to nullptr, and subsequent call will check this fact and doesn't do anything. That's why you can add a Reset() before Dispose() to avoid the UB.
That's also true for your Global<Context>, it doesn't demonstrate itself because access-after-free doesn't always trigger a segfault.
Is there a reason, whyGlobal::Reset()is not automatically called on all registered global objects whenIsolate::Dispose()is invoked?
– mhk
Dec 31 '18 at 15:10
@mhkGlobalessentially contains a pointer to the storage node.Isolatehas no way to change that pointer value. BecauseIsolatedoesn't know where theGlobalis in user's code.
– llllllllll
Dec 31 '18 at 15:15
add a comment |
v8::Globalhas a destructor that will callReset().The global handles are held in the
Isolate, afterIsolate::Dispose(), the global handles will be freed.
Thus, if you don't call Global::Reset(), but Dispose the Isolate before the destruction of a Global, the destructor of Global will cause a access-after-free, which is a typical Undefined Behavior.
Reset() will set the internal pointer to nullptr, and subsequent call will check this fact and doesn't do anything. That's why you can add a Reset() before Dispose() to avoid the UB.
That's also true for your Global<Context>, it doesn't demonstrate itself because access-after-free doesn't always trigger a segfault.
v8::Globalhas a destructor that will callReset().The global handles are held in the
Isolate, afterIsolate::Dispose(), the global handles will be freed.
Thus, if you don't call Global::Reset(), but Dispose the Isolate before the destruction of a Global, the destructor of Global will cause a access-after-free, which is a typical Undefined Behavior.
Reset() will set the internal pointer to nullptr, and subsequent call will check this fact and doesn't do anything. That's why you can add a Reset() before Dispose() to avoid the UB.
That's also true for your Global<Context>, it doesn't demonstrate itself because access-after-free doesn't always trigger a segfault.
answered Dec 31 '18 at 6:14
llllllllllllllllllll
13.7k41742
13.7k41742
Is there a reason, whyGlobal::Reset()is not automatically called on all registered global objects whenIsolate::Dispose()is invoked?
– mhk
Dec 31 '18 at 15:10
@mhkGlobalessentially contains a pointer to the storage node.Isolatehas no way to change that pointer value. BecauseIsolatedoesn't know where theGlobalis in user's code.
– llllllllll
Dec 31 '18 at 15:15
add a comment |
Is there a reason, whyGlobal::Reset()is not automatically called on all registered global objects whenIsolate::Dispose()is invoked?
– mhk
Dec 31 '18 at 15:10
@mhkGlobalessentially contains a pointer to the storage node.Isolatehas no way to change that pointer value. BecauseIsolatedoesn't know where theGlobalis in user's code.
– llllllllll
Dec 31 '18 at 15:15
Is there a reason, why
Global::Reset() is not automatically called on all registered global objects when Isolate::Dispose() is invoked?– mhk
Dec 31 '18 at 15:10
Is there a reason, why
Global::Reset() is not automatically called on all registered global objects when Isolate::Dispose() is invoked?– mhk
Dec 31 '18 at 15:10
@mhk
Global essentially contains a pointer to the storage node. Isolate has no way to change that pointer value. Because Isolate doesn't know where the Global is in user's code.– llllllllll
Dec 31 '18 at 15:15
@mhk
Global essentially contains a pointer to the storage node. Isolate has no way to change that pointer value. Because Isolate doesn't know where the Global is in user's code.– llllllllll
Dec 31 '18 at 15:15
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982229%2fv8-segfault-when-using-global-with-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown