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:
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
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue