2012-07-16 3 views
3

배경 : 데모 용 및 학습용으로 node.js 복제본을 만들려고합니다.v8 객체 수명에 대한 혼란

콜백 호출을 시도 할 때 segfault가 발생합니다. C++에서 javascript의 개체에 연결했습니다. obj->Set(xxx, callback)을 사용하여 개체에 값을 할당하고 있습니다. http 요청이 발생할 때마다 해당 객체로 돌아가 obj->Get(xxx)을 사용하여 해당 콜백을 가져오고 호출하려고 시도합니다. 그러나 포인터로 작업 할 때 segfault가 발생합니다. 또한 available on Github

#include "HttpWrap.h" 
#include <cstdlib> 
#include "v8/include/v8.h" 
#include "libuv/include/uv.h" 

using namespace v8; 

HttpWrap::HttpWrap(const Arguments& args) 
{ 
    Local<ObjectTemplate> serverTemplate = ObjectTemplate::New(); 
    serverTemplate->SetInternalFieldCount(1); 
    serverTemplate->Set(String::New("listen"), FunctionTemplate::New(Listen)); 

    Local<Object> localServer = serverTemplate->NewInstance(); 
    localServer->SetInternalField(0, External::New(this)); 

    String::AsciiValue ip_address(args[0]); 
    int port = args[1]->Int32Value(); 

    handle = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); 
    uv_tcp_init(uv_default_loop(), handle); 
    handle->data = this; 
    uv_tcp_bind(handle, uv_ip4_addr(*ip_address, port)); 

    server = Persistent<Object>::New(localServer); 
} 

Handle<Value> HttpWrap::Listen(const Arguments& args) 
{ 
    puts("HttpWrap::Listen"); 

    HandleScope scope; 

    Local<External> wrap = Local<External>::Cast(args.Holder()->GetInternalField(0)); 
    HttpWrap* httpWrap = static_cast<HttpWrap*>(wrap->Value()); 
    httpWrap->server->Set(String::New("onrequest"), args[0]); 
    uv_listen((uv_stream_t*) httpWrap->handle, 128, OnConnection); 

    return scope.Close(Undefined()); 
} 

void HttpWrap::OnConnection(uv_stream_t* handle, int status) 
{ 
    puts("HttpWrap::OnConnection"); 
    uv_tcp_t* client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); 
    uv_tcp_init(uv_default_loop(), client); 
    client->data = handle->data; 
    uv_accept(handle, (uv_stream_t*) client); 
    uv_read_start((uv_stream_t*) client, AllocConnection, OnRead); 
} 

uv_buf_t HttpWrap::AllocConnection(uv_handle_t* handle, size_t suggested_size) 
{ 
    puts("HttpWrap::AllocConnection"); 
    return uv_buf_init((char*) malloc(suggested_size), suggested_size); 
} 

void HttpWrap::OnRead(uv_stream_t* server, ssize_t nread, uv_buf_t buf) 
{ 
    HandleScope scope; 
    puts("HttpWrap::OnRead"); 

    HttpWrap* httpWrap = static_cast<HttpWrap*>(server->data); 
    Local<String> callbackSym = String::New("onrequest"); 
    Local<Value> value = httpWrap->server->Get(callbackSym); 

    if (!value->IsFunction()) 
    { 
     puts("Value is not a function"); 
    } 
    else 
    { 
     puts("Value is a function"); 
     Local<Function> callback = Local<Function>::Cast(value); 
     Local<Value>* argv = new Local<Value>[1]; 
     argv[0] = String::New("test"); 
     puts("Invoking callback"); 
     callback->Call(Context::GetCurrent()->Global(), 1, argv); 
     puts("invoked callback"); 
    } 

    free(buf.base); 
    uv_close((uv_handle_t*) server, OnClose); 
} 

void HttpWrap::OnClose(uv_handle_t* handle) 
{ 
    puts("HttpWrap::OnClose"); 
} 

:

여기에 코드입니다.

대상 라인은 36과 65입니다. 세그 폴트는 callback->Call을 호출 할 때마다 발생합니다.

어떤 생각이나 좋은 습관이라면 크게 환영합니다!

답변

1

불행히도이 문제를 해결하기 위해 약간의 터널 비전이 있습니다. 주요 문제는 콜백 호출을 시도하기 전에 주 컨텍스트를 삭제하고 있다는 것이 었습니다. js 공간에서 코드를 호출하려는 컨텍스트가 폐기되었으므로 실패했습니다.

+1

크래시가 발생하고 디버거에서 검사 할 때 관련 포인터와 해당 포인터가 가리키는 구조가 유효한지 항상 확인하십시오. 예를 들어 GDB는'print callback','print * callback','print callback-> Call'과 같은 것이 될 것입니다. –