Skip to content
Snippets Groups Projects
Commit 413bd994 authored by Enric Tejedor Saavedra's avatar Enric Tejedor Saavedra
Browse files

[ROOT-9809] Only invoke Python C API if Python is initialized

If libPyROOT is loaded with gSystem->Load, the static
initialization block in TMemoryRegulator.cxx is executed and
ends up invoking PyCFunction_New, which causes a crash from
Python 3.7. The crash is due to Python not being initialized.
This also happens when using TPython from C++, since Python
has not	been initialized when TPython is used.

Note that when loading libPyROOT from ROOT.py, which is what
happens when someone uses PyROOT, the Python interpreter already
exists and is initialized, so invoking PyCFunction_New does not
crash.

This fix moves the creation of gObjectEraseCallback away from
the static block in TMemoryRegulator in order to prevent the
issue described above.
parent 17d499c1
No related merge requests found
...@@ -20,16 +20,13 @@ PyROOT::TMemoryRegulator::WeakRefMap_t* PyROOT::TMemoryRegulator::fgWeakRefTable ...@@ -20,16 +20,13 @@ PyROOT::TMemoryRegulator::WeakRefMap_t* PyROOT::TMemoryRegulator::fgWeakRefTable
namespace { namespace {
// memory regulater callback for deletion of registered objects // memory regulater callback for deletion of registered objects
PyMethodDef methoddef_ = { PyMethodDef gObjectEraseMethodDef = {
const_cast< char* >( "TMemoryRegulator_internal_ObjectEraseCallback" ), const_cast< char* >( "TMemoryRegulator_internal_ObjectEraseCallback" ),
(PyCFunction) PyROOT::TMemoryRegulator::ObjectEraseCallback, (PyCFunction) PyROOT::TMemoryRegulator::ObjectEraseCallback,
METH_O, METH_O,
NULL NULL
}; };
PyObject* gObjectEraseCallback = PyCFunction_New( &methoddef_, NULL );
// pseudo-None type for masking out objects on the python side // pseudo-None type for masking out objects on the python side
PyTypeObject PyROOT_NoneType; PyTypeObject PyROOT_NoneType;
...@@ -199,13 +196,15 @@ void PyROOT::TMemoryRegulator::RecursiveRemove( TObject* object ) ...@@ -199,13 +196,15 @@ void PyROOT::TMemoryRegulator::RecursiveRemove( TObject* object )
Bool_t PyROOT::TMemoryRegulator::RegisterObject( ObjectProxy* pyobj, TObject* object ) Bool_t PyROOT::TMemoryRegulator::RegisterObject( ObjectProxy* pyobj, TObject* object )
{ {
static PyObject* objectEraseCallback = PyCFunction_New(&gObjectEraseMethodDef, nullptr);
if ( ! ( pyobj && object ) ) if ( ! ( pyobj && object ) )
return kFALSE; return kFALSE;
ObjectMap_t::iterator ppo = fgObjectTable->find( object ); ObjectMap_t::iterator ppo = fgObjectTable->find( object );
if ( ppo == fgObjectTable->end() ) { if ( ppo == fgObjectTable->end() ) {
object->SetBit( TObject::kMustCleanup ); object->SetBit( TObject::kMustCleanup );
PyObject* pyref = PyWeakref_NewRef( (PyObject*)pyobj, gObjectEraseCallback ); PyObject* pyref = PyWeakref_NewRef( (PyObject*)pyobj, objectEraseCallback );
ObjectMap_t::iterator newppo = fgObjectTable->insert( std::make_pair( object, pyref ) ).first; ObjectMap_t::iterator newppo = fgObjectTable->insert( std::make_pair( object, pyref ) ).first;
(*fgWeakRefTable)[ pyref ] = newppo; // no Py_INCREF on pyref, as object table has one (*fgWeakRefTable)[ pyref ] = newppo; // no Py_INCREF on pyref, as object table has one
return kTRUE; return kTRUE;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment