, globals=, locals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'cppdef': , 'cppexec': , 'include': , 'c_include': , 'load_library': , 'nullptr': , 'sizeof': , 'typeid': , 'multi': , 'add_include_path': , 'add_library_path': , 'add_autoload_map': , 'set_debug': , 'c': <_meta(__module__='cppyy._cpython_cppyy', __dict__=, __weakref__=, __doc_...(truncated)) at /usr/src/debug/python3.11-3.11.5-1.fc38.x86_64/Python/ceval.c:1154
#25 0x00007fa6d9057c33 in run_eval_code_obj (tstate=tstate
entry=0x7fa6d930ed38 <_PyRuntime+166328>, co=co
entry=0x7fa6cb363930, globals=globals
entry={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'cppdef': , 'cppexec': , 'include': , 'c_include': , 'load_library': , 'nullptr': , 'sizeof': , 'typeid': , 'multi': , 'add_include_path': , 'add_library_path': , 'add_autoload_map': , 'set_debug': , 'c': <_meta(__module__='cppyy._cpython_cppyy', __dict__=, __weakref__=, __doc_...(truncated), locals=locals
entry={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'cppdef': , 'cppexec': , 'include': , 'c_include': , 'load_library': , 'nullptr': , 'sizeof': , 'typeid': , 'multi': , 'add_include_path': , 'add_library_path': , 'add_autoload_map': , 'set_debug': , 'c': <_meta(__module__='cppyy._cpython_cppyy', __dict__=, __weakref__=, __doc_...(truncated)) at /usr/src/debug/python3.11-3.11.5-1.fc38.x86_64/Python/pythonrun.c:1712
#26 0x00007fa6d90542fa in run_mod (mod=mod
entry=0x56112f057910, filename=filename
entry='', globals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'cppdef': , 'cppexec': , 'include': , 'c_include': , 'load_library': , 'nullptr': , 'sizeof': , 'typeid': , 'multi': , 'add_include_path': , 'add_library_path': , 'add_autoload_map': , 'set_debug': , 'c': <_meta(__module__='cppyy._cpython_cppyy', __dict__=, __weakref__=, __doc_...(truncated), locals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'cppdef':
I found some weird crashes when implementing a C++ observer interface in Python. The interface is implemented as follows:
test.cpp (click me)
```cpp #include#include
#include
#include
struct Observable;
struct Observer {
Observable *observed = nullptr;
std::list::iterator it;
virtual ~Observer() {
observe(nullptr);
}
void observe(Observable *observable);
virtual void onThingDone(const std::string &msg) = 0;
virtual void onRegistered(Observable *previous) {};
};
struct Observable {
std::list observers;
~Observable() {
while (!observers.empty())
observers.front()->observe(nullptr);
}
void doThing(const std::string &msg) {
for (auto o: observers)
o->onThingDone(msg);
}
void registerObserver(Observer *obs) {
assert(obs != nullptr);
assert(obs->observed == nullptr);
observers.push_back(obs);
obs->it = observers.end();
--obs->it;
obs->observed = this;
obs->onRegistered(nullptr);
}
void unregisterObserver(Observer *obs) {
assert(obs != nullptr);
assert(obs->observed == this);
observers.erase(obs->it);
obs->it = std::list::iterator{};
obs->observed = nullptr;
obs->onRegistered(this);
}
};
void Observer::observe(Observable *observable) {
if (observed)
observed->unregisterObserver(this);
if (observable)
observable->registerObserver(this);
}
struct MyObserver : Observer {
MyObserver() {
std::cout << this << " construct" << std::endl;
}
~MyObserver() {
std::cout << this << " destruct" << std::endl;
}
void onThingDone(const std::string &msg) override {
std::cout << this << " onThingDone " << msg << std::endl;
}
void onRegistered(Observable *previous) override {
std::cout << this << " onRegistered(was " << previous << " is " << observed << ")" << std::endl;
}
};
MyObserver long_lived_obs;
int main() {
Observable obj;
long_lived_obs.observe(&obj);
MyObserver obs;
obs.observe(&obj);
obj.doThing("1");
{
MyObserver obs2;
obs2.observe(&obj);
obj.doThing("2");
}
{
MyObserver obs3;
obs3.observe(&obj);
obj.doThing("3");
}
obj.doThing("4");
return 0;
}
```
When directly running the tests in a compiled version of
main
, everything works and evenvalgrind
is happy. When doing a similar thing via cppyy 2.4.2, I get an interpreter crash:Re-running the last three lines (excluding the creation of obj) or running
del obs
results in the following interpreter crash either immediately or upon exiting the python interpreter:I also got this pretty arbitrary backtrace when trying to do dome more logging and exception handling in a
__del__
method.Doing the same thing with cppyy 3.0 yields the following:
Note that I get those
Failed to materialize symbols
errors all the time, which is why I tend to prefer 2.4 over 3.0.