Fix T98427: Crash adding quick effects smoke from Python

Manta flow used the `__main__` namespace which it was executed in,
this caused a bug when calculating fluid from Python, which clears
it's `__main__` name-space after execution.
This caused Manta-flows name space to be cleared too.

Resolve this by creating a separate name-space for manta-flow.

Reviewed by: SonnyCampbell_Unity

Ref D15269
This commit is contained in:
Campbell Barton 2022-06-24 23:28:19 +10:00
parent 2580d2bab5
commit ad8add5f0c
Notes: blender-bot 2023-02-14 06:19:41 +01:00
Referenced by issue #98427, Adding quick effects smoke with python raises segmentation fault
3 changed files with 93 additions and 14 deletions

View File

@ -115,7 +115,7 @@ class WrapperRegistry {
void construct(const std::string &scriptname, const vector<string> &args);
void cleanup();
void renameObjects();
void runPreInit();
void runPreInit(PyObject *name_space);
PyObject *initModule();
ClassData *lookup(const std::string &name);
bool canConvert(ClassData *from, ClassData *to);
@ -505,7 +505,7 @@ void WrapperRegistry::addConstants(PyObject *module)
}
}
void WrapperRegistry::runPreInit()
void WrapperRegistry::runPreInit(PyObject *name_space)
{
// add python directories to path
PyObject *sys_path = PySys_GetObject((char *)"path");
@ -518,7 +518,15 @@ void WrapperRegistry::runPreInit()
}
if (!mCode.empty()) {
mCode = "from manta import *\n" + mCode;
PyRun_SimpleString(mCode.c_str());
PyObject *return_value = PyRun_String(mCode.c_str(), Py_file_input, name_space, name_space);
if (return_value == nullptr) {
if (PyErr_Occurred()) {
PyErr_Print();
}
}
else {
Py_DECREF(return_value);
}
}
}
@ -698,11 +706,11 @@ PyObject *WrapperRegistry::initModule()
//******************************************************
// Register members and exposed functions
void setup(const std::string &filename, const std::vector<std::string> &args)
void setup(const std::string &filename, const std::vector<std::string> &args, PyObject *name_space)
{
WrapperRegistry::instance().construct(filename, args);
Py_Initialize();
WrapperRegistry::instance().runPreInit();
WrapperRegistry::instance().runPreInit(name_space);
}
void finalize()

View File

@ -48,7 +48,7 @@ template<class T> struct Namify {
namespace Pb {
// internal registry access
void setup(const std::string &filename, const std::vector<std::string> &args);
void setup(const std::string &filename, const std::vector<std::string> &args, PyObject *name_space);
void finalize();
bool canConvert(PyObject *obj, const std::string &to);
Manta::PbClass *objFromPy(PyObject *obj);

View File

@ -567,10 +567,53 @@ MANTA::~MANTA()
}
/**
* Store a pointer to the __main__ module used by mantaflow. This is necessary, because sometimes
* Blender will overwrite that module. That happens when e.g. scripts are executed in the text
* editor.
*
* Copied from `PyC_DefaultNameSpace` in Blender.
* with some differences:
* - Doesn't touch `sys.modules`, use #manta_python_main_module_activate instead.
* - Returns the module instead of the modules `dict`.
* */
static PyObject *manta_python_main_module_create(const char *filename)
{
PyObject *builtins = PyEval_GetBuiltins();
PyObject *mod_main = PyModule_New("__main__");
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
if (filename) {
/* __file__ mainly for nice UI'ness
* NOTE: this won't map to a real file when executing text-blocks and buttons. */
PyModule_AddObject(mod_main, "__file__", PyUnicode_InternFromString(filename));
}
PyModule_AddObject(mod_main, "__builtins__", builtins);
Py_INCREF(builtins); /* AddObject steals a reference */
return mod_main;
}
static void manta_python_main_module_activate(PyObject *mod_main)
{
PyObject *modules = PyImport_GetModuleDict();
PyObject *main_mod_cmp = PyDict_GetItemString(modules, "__main__");
if (mod_main == main_mod_cmp) {
return;
}
/* NOTE: we could remove the reference to `mod_main` here, but as it's know to be removed
* accept that there is temporarily an extra reference. */
PyDict_SetItemString(modules, "__main__", mod_main);
}
static void manta_python_main_module_backup(PyObject **r_main_mod)
{
PyObject *modules = PyImport_GetModuleDict();
*r_main_mod = PyDict_GetItemString(modules, "__main__");
Py_XINCREF(*r_main_mod); /* don't free */
}
static void manta_python_main_module_restore(PyObject *main_mod)
{
PyObject *modules = PyImport_GetModuleDict();
PyDict_SetItemString(modules, "__main__", main_mod);
Py_XDECREF(main_mod);
}
/**
* Mantaflow stores many variables in the globals() dict of the __main__ module. To be able to
* access these variables, the same __main__ module has to be used every time.
*
@ -579,14 +622,35 @@ MANTA::~MANTA()
*/
static PyObject *manta_main_module = nullptr;
static void manta_python_main_module_clear()
{
if (manta_main_module) {
Py_DECREF(manta_main_module);
manta_main_module = nullptr;
}
}
static PyObject *manta_python_main_module_ensure()
{
if (!manta_main_module) {
manta_main_module = manta_python_main_module_create("<manta_namespace>");
}
return manta_main_module;
}
bool MANTA::runPythonString(vector<string> commands)
{
bool success = true;
PyGILState_STATE gilstate = PyGILState_Ensure();
if (manta_main_module == nullptr) {
manta_main_module = PyImport_ImportModule("__main__");
}
/* Temporarily set `sys.modules["__main__"]` as some Python modules expect this. */
PyObject *main_mod_backup;
manta_python_main_module_backup(&main_mod_backup);
/* If we never want to run this when the module isn't initialize,
* assign with `manta_python_main_module_ensure()`. */
BLI_assert(manta_main_module != nullptr);
manta_python_main_module_activate(manta_main_module);
for (vector<string>::iterator it = commands.begin(); it != commands.end(); ++it) {
string command = *it;
@ -605,6 +669,9 @@ bool MANTA::runPythonString(vector<string> commands)
Py_DECREF(return_value);
}
}
manta_python_main_module_restore(main_mod_backup);
PyGILState_Release(gilstate);
BLI_assert(success);
@ -622,7 +689,10 @@ void MANTA::initializeMantaflow()
/* Initialize extension classes and wrappers. */
srand(0);
PyGILState_STATE gilstate = PyGILState_Ensure();
Pb::setup(filename, fill); /* Namespace from Mantaflow (registry). */
PyObject *manta_main_module = manta_python_main_module_ensure();
PyObject *globals_dict = PyModule_GetDict(manta_main_module);
Pb::setup(filename, fill, globals_dict); /* Namespace from Mantaflow (registry). */
PyGILState_Release(gilstate);
}
@ -633,6 +703,7 @@ void MANTA::terminateMantaflow()
PyGILState_STATE gilstate = PyGILState_Ensure();
Pb::finalize(); /* Namespace from Mantaflow (registry). */
manta_python_main_module_clear();
PyGILState_Release(gilstate);
}