marylinh / pyv8

Automatically exported from code.google.com/p/pyv8
0 stars 0 forks source link

Segfault on V8 Garbage Collection with Custom Python Exception. #84

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
This was a really hard problem to diagnose until I dived into the source code a 
bit.  Basically here is the python code that will trigger the segfault:

import PyV8

class CustomException(Exception):

    def __init__(self, status):
        self.status = status

    def __str__(self):
        print self.status

class Global():
    def __init__(self):
        self.error = None

    def raiseError(self):
        raise CustomException("status")

# Keep running in a loop to force V8 garbage collection.
for i in range(0, 1000):
    print "%s" % i

    errors = []
    with PyV8.JSContext(Global()) as ctx:
        try:
            ctx.eval(""" raiseError() """)  
        except Exception, e:
            errors.append(e)

This all stems from an issue thats commented in the source code to fix in 
Wrapper.cpp:

 if (error->IsObject())

  {

    // FIXME How to trace the lifecycle of exception? and when to delete those object in the hidden value?

  #ifdef SUPPORT_TRACE_LIFECYCLE

    error->ToObject()->SetHiddenValue(v8::String::NewSymbol("exc_type"), v8::External::New(ObjectTracer::Trace(error, new py::object(type)).Object()));

    error->ToObject()->SetHiddenValue(v8::String::NewSymbol("exc_value"), v8::External::New(ObjectTracer::Trace(error, new py::object(value)).Object()));

  #else

    error->ToObject()->SetHiddenValue(v8::String::NewSymbol("exc_type"), v8::External::New(new py::object(type)));

    error->ToObject()->SetHiddenValue(v8::String::NewSymbol("exc_value"), v8::External::New(new py::object(value)));

  #endif

The actual segfault happens in the ObjectTracer destructor:

m_object.reset();

Here, the PyObject* pointed to by the py::object pointed to by the 
std::auto_ptr m_object is already deallocated.   

I added this code to test that theory:

if(m_object->ptr() == NULL) {
  std::cout << "Pointer Is Null" << std::endl;
}

A backtrace from gdb is below.  You can see the V8 garbage collector running, 
calling the WeakCallback for ObjectTracer and then calling ObjectTracer 
destructor and thus the py_objects destructor:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff5ec8552 in ~object_base (this=0x9eefa0, __in_chrg=<value optimized 
out>)
    at /usr/include/boost/python/object_core.hpp:509
509     Py_DECREF(m_ptr);
(gdb) bt
#0  0x00007ffff5ec8552 in ~object_base (this=0x9eefa0, __in_chrg=<value 
optimized out>)
    at /usr/include/boost/python/object_core.hpp:509
#1  ~object (this=0x9eefa0, __in_chrg=<value optimized out>) at 
/usr/include/boost/python/object_core.hpp:311
#2  std::auto_ptr<boost::python::api::object>::reset (this=0x9eefa0, 
__in_chrg=<value optimized out>)
    at /usr/include/c++/4.4/backward/auto_ptr.h:242
#3  ~ObjectTracer (this=0x9eefa0, __in_chrg=<value optimized out>) at 
src/Wrapper.cpp:1791
#4  0x00007ffff5ec86e1 in ~auto_ptr (value=<value optimized out>, 
parameter=0x9eefa0)
    at /usr/include/c++/4.4/backward/auto_ptr.h:168
#5  ObjectTracer::WeakCallback (value=<value optimized out>, 
parameter=0x9eefa0) at src/Wrapper.cpp:1842
#6  0x00007ffff5fd5aec in 
v8::internal::GlobalHandles::Node::PostGarbageCollectionProcessing 
(this=0x7ffff52e9008, 
    isolate=0x962cc0, global_handles=0x93d250) at src/global-handles.cc:201

Possible Causes:

Not really that sure yet.  Could this be caused by python's garbage collector?

Temp Solutions:  

I just commented out the code that is trying to trace exceptions.  I suggest 
that you should do this until there is a safe way to trace exceptions so people 
don't run into this strange segfault.  It took me quite a while to figure out 
where the problem was occurring, and I still don't have an exact cause.    

Original issue reported on code.google.com by mbc8...@gmail.com on 22 Apr 2011 at 3:35

GoogleCodeExporter commented 9 years ago
Sorry for the immature code, I agree that the object tracer is a experimental 
feature, it's hard to trace some special object including the exception.

It seems Python collect the exception, even it's object refcount is not zero, I 
have disable it by default, maybe we could find some methods to trace it, 
please verify it with pyv8 SVN trunk code after r369.

Thanks for your notification :)

Original comment by flier...@gmail.com on 24 Apr 2011 at 4:08

GoogleCodeExporter commented 9 years ago

Original comment by flier...@gmail.com on 24 Apr 2011 at 4:09