Python中出错后Py_Finalize()崩溃

1 投票
3 回答
4869 浏览
提问于 2025-04-16 21:53

我正在尝试使用 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 时自动处理模块的引用,不需要你额外做什么。

撰写回答