[C++-sig] Segfaults in object deallocation

Alex Leach beamesleach at gmail.com
Wed Mar 20 15:46:59 CET 2013


Dear list,

I've started using Boost.Python to wrap a 3rd party C++ library, and  
whilst running my unit tests, the Python interpreter segfault's during  
garbage collection.

With explicit object deletion:

$ gdb -q --args python -c 'import mylib; obj = mylib.MyObj(); del(obj)'
...
*** Error in `/usr/bin/python': free(): invalid next size (fast):  
0x0000000000806fd0 ***
======= Backtrace: =========
/usr/lib/libc.so.6(+0x7ab06)[0x7ffff74d3b06]
/usr/lib/libc.so.6(+0x7b883)[0x7ffff74d4883]
/usr/lib/libboost_python.so.1.53.0(_ZN5boost6python15instance_holder10deallocateEP7_objectPv+0x15)[0x7ffff004f555]
/usr/lib/libboost_python.so.1.53.0(+0x265a1)[0x7ffff004f5a1]
...
======= Memory map: ========
...


or, leaving it to the garbage collector:-

$ gdb -q --args python -c 'import mylib; obj = mylib.obj() '
...
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b2b0b0 in visit_decref () from /usr/lib/libpython2.7.so.1.0
(gdb)

Quick question: What do I need to do to fix this?

==========================
--- The wrapper class  ---

The wrapper class I've written is fairly simple; I haven't explicitly  
added a 'PyObject* _self' attribute, nor done any of the wiki  
recommendations[3] for managing ownership, as I don't see anywhere in the  
tutorial that recommends any of these methods.

------------------------------------
--- Using boost::python::wrapper ---

The wrapped class (in 3rd party library) does have one virtual method  
(that is protected and I haven't exposed to Python) and a virtual  
destructor. I gather the right thing to do with virtual classes is to also  
inherit from 'boost::python::wrapper<Base>', but this doesn't affect the  
seg-fault. I guess I don't need to inherit from wrapper<Base>, as I am not  
exposing any virtual methods, nor using 'this->get_override(...)' anywhere  
in the class definition.

Another very similar class is in the same source file though (virtual  
destructor and one unexposed virtual method), but this one has a public  
copy constructor. If I inherit from 'wrapper<Base>', I get a compilation  
error regarding an argument mismatch when Boost.Python passes the derived  
class to the copy constructor of the base class. Of course I can add  
noncopyable, to the class_<..> registration, but I'd like the exposed  
class to stay copyable, and I might like to use some of the wrapper  
template class' functionality. Should I wrap the copy constructor in the  
wrapper class too? Would it be possible to add this functionality to the  
wrapper<> template, when the class is not noncopyable?


------------------------------------
--- Calling thread-safe methods  ---

I don't think this is directly relevant, but the classes in question use  
the 3rd party library's own mutex implementations to ensure thread-safety.  
I've just got these working by writing a simple utility class that  
releases the GIL in the constructor and reacquires it in its destructor,  
using the C-Python API PyGILState_* functions[1].
The general tactic was described on the boost.python wiki[2], but the  
PyEval_(Save|Restore)Thread functions described caused the same assertion  
errors that I was getting earlier, with the pthreads mutex. This happened  
when the 3rd party library tried to lock the global mutex.

Although this is mentioned in the C-Python manual, I would have found it  
useful if thread-safety was specifically mentioned in the tutorial or  
reference manual somewhere... I attach the solution I wrote to this  
problem, in case someone would want to add it and document it in  
Boost.Python somewhere.

Usage:

  {
      MakeThreadsafe scope; //< GIL acquired
      // call function that acquires pthreads mutex.
  } //< GIL released when leave scope


------------------------------------
--- Garbage collection segfaul   ---

Any help with this would be really appreciated! I thought that registering  
a wrapped class with class_<...> was enough, to ensure an object's ref  
count was incremented and decremented properly. I guess that's the  
fundamentals of the problem, but am not sure the easiest / best / most  
efficient way of solving the problem.. Again, some specific documentation,  
on when and why this problem occurs and how to solve it, in the tutorial  
would be great!

Looking forward to hearing back...

Kind regards,
Alex


[1] - http://docs.python.org/2.7/c-api/init.html#non-python-created-threads
[2] -  
http://wiki.python.org/moin/boost.python/HowTo#Multithreading_Support_for_my_function
[3] -  
http://wiki.python.org/moin/boost.python/HowTo#ownership_of_C.2B-.2B-_object

-- 
Using Opera's mail client: http://www.opera.com/mail/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: make_threadsafe.hpp
Type: application/octet-stream
Size: 977 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20130320/dcfdacf3/attachment.obj>


More information about the Cplusplus-sig mailing list