From 07368885e3b7177b204890fffbf7ab5faa792c04 Mon Sep 17 00:00:00 2001 From: Dan White Date: Sun, 14 Jun 2026 13:34:06 -0600 Subject: [PATCH 1/2] Fix crash in Engine_Python_Tests from repeated Python initialization PythonInterpreter::initialize() is called in the GTest fixture constructor, which runs once per test on the singleton. The second call hit PyImport_AppendInittab() after Py_Initialize(), causing a fatal abort. Added an early-return guard so initialize() is idempotent. Co-Authored-By: Claude Sonnet 4.6 --- src/Core/Python/PythonInterpreter.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Core/Python/PythonInterpreter.cc b/src/Core/Python/PythonInterpreter.cc index 3f3bfb8b44..df34c43484 100644 --- a/src/Core/Python/PythonInterpreter.cc +++ b/src/Core/Python/PythonInterpreter.cc @@ -607,6 +607,9 @@ void PythonInterpreter::set_python_argv(const std::vector& argv) void PythonInterpreter::initialize(bool needProgramName, const std::string& commandLine, const boost::filesystem::path& libPath) { + if (this->private_->initialized_) + return; + const auto argv = argvFromFullString(commandLine); if (needProgramName) From c8d2613f88c67780f0a7cf88dc0cb02ab8626875 Mon Sep 17 00:00:00 2001 From: Dan White Date: Sun, 14 Jun 2026 16:06:32 -0600 Subject: [PATCH 2/2] Fix data race on SimpleMapModuleState::transientStateMap_ (fixes #2486) transientStateMap_ was accessed concurrently from the GUI thread and async module execution threads (e.g. ViewScene streaming), causing rare heap corruption under parallel test load. Add a mutex protecting all transientStateMap_ reads and writes in getTransientValue, setTransientValue, and print(). Signals are fired after releasing the lock to avoid re-entrancy from signal handlers that call back into get/setTransientValue. Copy ctor and copy assignment also lock the source object's mutex while reading transientStateMap_. Co-Authored-By: Claude Sonnet 4.6 --- src/Dataflow/State/SimpleMapModuleState.cc | 17 ++++++++++++++--- src/Dataflow/State/SimpleMapModuleState.h | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Dataflow/State/SimpleMapModuleState.cc b/src/Dataflow/State/SimpleMapModuleState.cc index 4e2cc81a09..327584fc19 100644 --- a/src/Dataflow/State/SimpleMapModuleState.cc +++ b/src/Dataflow/State/SimpleMapModuleState.cc @@ -55,9 +55,10 @@ SimpleMapModuleState::SimpleMapModuleState(SimpleMapModuleState&& rhs) SimpleMapModuleState::SimpleMapModuleState(const SimpleMapModuleState& rhs) : stateMap_(rhs.stateMap_), - transientStateMap_(rhs.transientStateMap_), /// @todo: I think this is wrong, transient shouldn't be copied name_(rhs.name_) { + std::lock_guard lock(rhs.transientMutex_); + transientStateMap_ = rhs.transientStateMap_; /// @todo: I think this is wrong, transient shouldn't be copied //std::cout << "SMMS copy ctor " << name_ << std::endl; } @@ -66,7 +67,10 @@ SimpleMapModuleState& SimpleMapModuleState::operator=(const SimpleMapModuleState if (&rhs != this) { stateMap_ = rhs.stateMap_; - transientStateMap_ = rhs.transientStateMap_; /// @todo: I think this is wrong, transient shouldn't be copied + { + std::lock_guard lock(rhs.transientMutex_); + transientStateMap_ = rhs.transientStateMap_; /// @todo: I think this is wrong, transient shouldn't be copied + } name_ = rhs.name_; //std::cout << "SMMS copy assign " << name_<< std::endl; /// @todo?? @@ -151,6 +155,7 @@ ModuleStateInterface::Keys SimpleMapModuleState::getKeys() const void SimpleMapModuleState::print() const { + std::lock_guard lock(transientMutex_); std::cout << "Printing transient map: " << this << " name: " << name_ << std::endl; for (auto q = transientStateMap_.begin(); q != transientStateMap_.end(); ++q) { @@ -161,6 +166,7 @@ void SimpleMapModuleState::print() const SimpleMapModuleState::TransientValueOption SimpleMapModuleState::getTransientValue(const Name& name) const { + std::lock_guard lock(transientMutex_); //print(); auto i = transientStateMap_.find(name.name()); return i != transientStateMap_.end() && !i->second.empty() ? std::optional(i->second) : TransientValueOption(); @@ -168,9 +174,14 @@ SimpleMapModuleState::TransientValueOption SimpleMapModuleState::getTransientVal void SimpleMapModuleState::setTransientValue(const Name& name, const TransientValue& value, bool fireSignal) { - transientStateMap_[name.name()] = value; + { + std::lock_guard lock(transientMutex_); + transientStateMap_[name.name()] = value; + } //print(); + // Fire signals outside the lock to avoid re-entrancy through signal handlers + // that call back into get/setTransientValue. if (fireSignal) { fireTransientStateChangeSignal(); diff --git a/src/Dataflow/State/SimpleMapModuleState.h b/src/Dataflow/State/SimpleMapModuleState.h index ae3421bcbd..ad53e542f3 100644 --- a/src/Dataflow/State/SimpleMapModuleState.h +++ b/src/Dataflow/State/SimpleMapModuleState.h @@ -31,6 +31,7 @@ #define DATAFLOW_STATE_SIMPLEMAPMODULESTATE_H #include +#include #include #include @@ -64,6 +65,7 @@ namespace State { StateMap stateMap_; typedef std::map TransientStateMap; TransientStateMap transientStateMap_; + mutable std::mutex transientMutex_; state_changed_sig_t stateChangedSignal_; provenance_state_changed_sig_t provenanceStateChangedSignal_; std::map specificStateChangeSignalMap_;