Pulse 4.4.0 Python API on aarch64 Linux: set_event_handler AttributeError, pull_active_events type, and abort in ~SESubstance at engine teardown

Apologies if there is a formal bug reporting mechanism.

I built Pulse 4.4.0 from source to use the Python API and ran the shipped HowTo examples. I found three problems, described below with steps to reproduce. I’m happy to test fixes or provide more detail.

Environment

  • Pulse: tag REL_4_4_0, commit 5e29e5b13 (the engine prints “Using Pulse Version 4.4.0-5e29e5b13”)
  • OS: Ubuntu 26.04.1 LTS, aarch64, in a virtual machine on Apple Silicon
  • Python: 3.15.1 in a virtual environment created by uv, with protobuf 7.35.0 and pip 26.2.2 (the build reported C++ protobuf 35.0)
  • Tools: GCC 15.2.0, CMake 4.2.3, Java 25.0.4.1
  • Build: default superbuild, cmake -DCMAKE_BUILD_TYPE:STRING=Release ../engine, then cmake --build .. The build completed, including the engine’s own data-generation step.
  • Examples were run from install/bin with PYTHONPATH set to install/python and install/bin.

1. PulseEngine.set_event_handler raises AttributeError

Running the unmodified src/python/pulse/howto/HowTo_EngineUse.py:

Using Pulse Version 4.4.0-5e29e5b13
Traceback (most recent call last):
  File ".../howto/HowTo_EngineUse.py", line 226, in <module>
    HowTo_UseEngine()
  File ".../howto/HowTo_EngineUse.py", line 66, in HowTo_UseEngine
    pulse.set_event_handler(local_event_handler())
  File ".../install/python/pulse/engine/PulseEngine.py", line 149, in set_event_handler
    self.__pulse.keep_event_changes(self._event_handler is not None)
AttributeError: 'PyPulse.Engine' object has no attribute 'keep_event_changes'. Did you mean '.pull_event_changes' instead of '.keep_event_changes'?

From the source: PulseEngine.py line 149 calls self.__pulse.keep_event_changes(...), but the pybind definitions in src/python/pybind/PulseEngines.cpp (line 33) define pull_event_changes, and the compiled module lists only pull_active_events and pull_event_changes among its event-related methods. keep_event_changes otherwise appears only as a data attribute (cdm/engine.py, cdm/io/engine.py). git log REL_4_4_0..origin/stable shows no later commits on the stable branch.

Is set_event_handler expected to work in 4.4.0, or should the wrapper do something different?

2. pull_active_events() returns a list, but HowTo_EngineUse.py expects a dict

With the line from (1) commented out in a copy of the script, the example runs the exercise section and prints vitals, then fails:

  File ".../howto_engineuse_test.py", line 211, in HowTo_UseEngine
    for event, duration_s in active_events.items():
AttributeError: 'list' object has no attribute 'items'

The comment in the script says “This is a map of event to duration (in seconds)”. Which is intended: should pull_active_events() return a mapping, or should the example be updated?

3. Abort “free(): corrupted unsorted chunks” when the engine is destroyed after the exception in (2)

After the traceback in (2), the process aborts. Running with python -X faulthandler shows the C stack passing through Pulse’s destructors (mangled names from the trace; my hand-demangled names alongside):

_ZN11SESubstanceD1Ev          SESubstance::~SESubstance()
_ZN18SESubstanceManagerD1Ev   SESubstanceManager::~SESubstanceManager()
_ZN5pulse10ControllerD1Ev     pulse::Controller::~Controller()
_ZN5pulse22human_adult_whole_body10ControllerD0Ev
_ZN5pulse6EngineD1Ev          pulse::Engine::~Engine()
_ZN5pulse22human_adult_whole_body6EngineD0Ev
_ZN16PulseEngineThunkD0Ev     PulseEngineThunk::~PulseEngineThunk()
... _Py_Dealloc

I can paste the full trace. Two runs that completed normally did not show this: the copy of HowTo_EngineUse.py with the .items() loop replaced by a print, and the unmodified HowTo_Exercise.py. Both exited with code 0. So it may only happen when the engine is destroyed without pulse.clear() having been called, for example after an uncaught exception, but I have not confirmed that. The process also had protobuf 7.35.0’s google._upb._message loaded alongside PyPulse, which statically includes protobuf 35.0; I don’t know whether that matters.

Is destroying a PulseEngine without calling clear() supported?

Minor note

The superbuild’s “Pip installing protobuf” step failed with “No module named pip” when the active Python environment was created by uv, which does not install pip by default. Adding pip to the environment fixed it. A line in the README might help others.

Thank you, and I’m glad to run any tests you suggest.

Thanks for the feedback

We are going over our Python to correct these issues and will be pushing a patch to the stable branch.

1 Like