Python中出错后Py_Finalize()崩溃
我正在尝试使用 Py_CompileString()
和 PyEval_EvalCode()
来调用一些 Python 代码。这一切都运行得很好,但当 Python 代码里面有错误时,调用 Py_Finalize()
就会崩溃。
Py_Initialize();
PyObject* code = Py_CompileString("pprint('Hello World')", "", Py_file_input);
PyObject* m = PyImport_AddModule("__main__");
PyObject* d = PyModule_GetDict(m);
Py_DECREF(m);
PyObject* r = PyEval_EvalCode(code, d, d);
Py_DECREF(d);
if (!r)
PyErr_Print();
Py_DECREF(code);
Py_Finalize();
输出结果是预期的:
Traceback (most recent call last):
File "", line 1, in <module>
NameError: name 'pprint' is no defined
但是在调用 Py_Finalize()
的时候,程序崩溃了。如果我把第三行改成
PyObject* code = Py_CompileString("print('Hello World')", "", Py_file_input);
程序就能正常运行并结束。到底出了什么问题呢?
如果我在 gdb 中运行这个程序,我得到了以下输出:
Windows:
Program received signal SIGSEGV, Segmentation fault.
0x1e01a030 in python32!PyType_IsSubtype () from C:\Windows\SysWOW64\python32.dll
Linux:
Program received signal SIGSEGV, Segmentation fault.
0xb7ef17bb in visit_decref (op=0xb78c87ec, data=0x0) at Modules/gcmodule.c:321
321 Modules/gcmodule.c: File or Directory not found.
in Modules/gcmodule.c
3 个回答
0
好的,我自己找到了错误。你只能在执行代码并检查错误之后,才可以调用 Py_DECREF(m)
。所以正确的程序是这样的:
Py_Initialize();
PyObject* code = Py_CompileString("pprint('Hello World')", "", Py_file_input);
PyObject* m = PyImport_AddModule("__main__");
PyObject* d = PyModule_GetDict(m);
PyObject* r = PyEval_EvalCode(code, d, d);
Py_DECREF(d);
if (!r)
PyErr_Print();
Py_DECREF(m);
Py_DECREF(code);
Py_Finalize();
1
if (!r) {
PyErr_Print();
PyErr_Clear();
}
这段话的意思是,它会清除错误,让你可以顺利地调用 Py_Finalize()
这个函数。
6
这个失败的真正原因不是因为你调用了 Py_DECREF
太早,而是因为你根本不应该调用它!
函数 PyImport_AddModule
返回的是一个 借用的 引用。这意味着,除非你真的掌控了这个引用(比如通过调用 Py_INCREF
来增加引用计数),否则你根本不可以调用 Py_DECREF
。
Python 会在调用 Py_Finalize
时自动处理模块的引用,不需要你额外做什么。