pmed / v8pp

Bind C++ functions and classes into V8 JavaScript engine
http://pmed.github.io/v8pp/
Other
901 stars 120 forks source link

Segmentation fault when cleaning up v8pp::context #35

Closed metalicjames closed 7 years ago

metalicjames commented 7 years ago

Hi,

When trying to execute the following code:

#include <iostream>
#include <v8.h>
#include <libplatform/libplatform.h>
#include <v8pp/context.hpp>

int main(int argc, char* argv[])
{
    v8::V8::InitializeICU();
    v8::V8::InitializeExternalStartupData(argv[0]);
    std::unique_ptr<v8::Platform> platform(v8::platform::CreateDefaultPlatform());
    v8::V8::InitializePlatform(platform.get());
    v8::V8::Initialize();

    v8pp::context context;

    const std::string source = "2 + 6";

    v8::Isolate* isolate = context.isolate();

    v8::HandleScope scope(isolate);
    v8::TryCatch tryCatch;
    v8::Handle<v8::Value> result = context.run_script(source);
    if(tryCatch.HasCaught())
    {
        const std::string msg = v8pp::from_v8<std::string>(isolate, tryCatch.Exception()->ToString());
    throw std::runtime_error(msg);
    }

    const int scriptResult = v8pp::from_v8<int>(isolate, result);

    std::cout << scriptResult;

    v8::V8::Dispose();
    v8::V8::ShutdownPlatform();

    return 0;
}

The program executes correctly and scriptResult contains 8 as expected. However, there is a segmentation fault when the deconstructor is called on v8pp::context context; with the following backtrace:

#0  0x00007ffff77c5177 in v8::internal::MemoryAllocator::Unmapper::FreeQueuedChunks() () from /usr/local/lib/libv8.so
No symbol table info available.
#1  0x00007ffff77c9187 in v8::internal::NewSpace::TearDown() () from /usr/local/lib/libv8.so
No symbol table info available.
#2  0x00007ffff777d5d9 in v8::internal::Heap::TearDown() () from /usr/local/lib/libv8.so
No symbol table info available.
#3  0x00007ffff783e7b4 in v8::internal::Isolate::Deinit() () from /usr/local/lib/libv8.so
No symbol table info available.
#4  0x00007ffff783e4d0 in v8::internal::Isolate::TearDown() () from /usr/local/lib/libv8.so
No symbol table info available.
#5  0x0000000000405eee in v8pp::context::~context() ()
No symbol table info available.
#6  0x0000000000403ec8 in main (argc=1, argv=0x7fffffffe508) at /home/james/workspace/v8test/main.cpp:20
        platform = std::unique_ptr<v8::Platform> containing 0x61fa30
        context = {
          own_isolate_ = true, 
          isolate_ = 0x620ef0, 
          impl_ = {
            <v8::PersistentBase<v8::Context>> = {
              val_ = 0x0
            }, <No data fields>}, 
          modules_ = std::map with 0 elements, 
          lib_path_ = ""
        }
        source = "2 + 6"
        isolate = 0x620ef0
        scope = {
          isolate_ = 0x620ef0, 
          prev_next_ = 0x0, 
          prev_limit_ = 0x0
        }
        tryCatch = {
          isolate_ = 0x620ef0, 
          next_ = 0x0, 
          exception_ = 0x17a028882351, 
          message_obj_ = 0x17a028882351, 
          js_stack_comparable_address_ = 0x7fffffffe288, 
          is_verbose_ = false, 
          can_continue_ = true, 
          capture_message_ = true, 
          rethrow_ = false, 
          has_terminated_ = false
        }
        result = {
          val_ = 0x671380
        }
        scriptResult = 8

Am I doing something wrong or is this a bug?

metalicjames commented 7 years ago

I have found the source of the problem. It is important for all v8pp objects to be deconstructed before calling v8::V8::Dispose(); otherwise there will be a segmentation fault. Putting the main bulk of the code in a try-catch clause fixed the problem.

pmed commented 7 years ago

Hi @metalicjames

Yes, you are absolutely right, all V8 and v8pp objects should be destroyed before v8::V8::Dispose() call.

I think here in your code should be a scope block for v8pp::context object. There is also a v8::HandleScope object in the code, but it is declared later, therefore it will be destroyed earlier than v8pp::context:

#include <iostream>
#include <v8.h>
#include <libplatform/libplatform.h>
#include <v8pp/context.hpp>

int main(int argc, char* argv[])
{
    v8::V8::InitializeICU();
    v8::V8::InitializeExternalStartupData(argv[0]);
    std::unique_ptr<v8::Platform> platform(v8::platform::CreateDefaultPlatform());
    v8::V8::InitializePlatform(platform.get());
    v8::V8::Initialize();

    // scope block for v8pp::context
    {
        v8pp::context context;

        const std::string source = "2 + 6";

        v8::Isolate* isolate = context.isolate();

        v8::HandleScope scope(isolate);
        v8::TryCatch tryCatch;
        v8::Handle<v8::Value> result = context.run_script(source);
        if (tryCatch.HasCaught())
        {
            const std::string msg = v8pp::from_v8<std::string>(isolate, tryCatch.Exception()->ToString());
            throw std::runtime_error(msg);
        }

        const int scriptResult = v8pp::from_v8<int>(isolate, result);

        std::cout << scriptResult;
    }
    v8::V8::Dispose();
    v8::V8::ShutdownPlatform();

    return 0;
}