V8 Segfault при использовании Global со значением - PullRequest
0 голосов
/ 31 декабря 2018

Я начинаю встраивать v8, и я сталкиваюсь с некоторым «неожиданным поведением».Следующий код выдает Segmentation fault (core dumped), когда переменная value_ не равна Reset в конце (см. Комментарий в коде).Однако то же самое не относится к контексту context_.Зачем? Этот ответ , похоже, связан, но не дает объяснения.

Я ожидал, что isolate->Dispose() позаботится об обоих.

#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;
}

Сборкаsetup:

Следуйте инструкциям в Запустите пример из официального Начало работы со встраиванием V8 .Сохраните код в sample / wasm.cc и выполните следующие команды:

$ g++ -I. -O2 -Iinclude samples/segfault.cc -o segfault  -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17
$ ./segfault

1 Ответ

0 голосов
/ 31 декабря 2018

Таким образом, если вы не вызовете Global::Reset(), но Dispose Isolate до уничтожения Global, деструктор Global вызовет access-after-free, который являетсяТипичное неопределенное поведение.

Reset() установит внутренний указатель на nullptr, и последующий вызов проверит этот факт и ничего не сделает.Вот почему вы можете добавить Reset() перед Dispose(), чтобы избежать UB.

Это также верно для вашего Global<Context>, он не демонстрирует себя, потому что access-after-free не всегда вызывает segfault.

...