Я пытаюсь вызвать некоторый код python, используя Py_CompileString()
и PyEval_EvalCode()
. Он отлично работает, но когда код 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()
программа сработает. Если я изменю строку 3 на
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
Фактическая причина этого не в том, что вы слишком рано вызываете Py_DECREF
. Это то, что вы звоните вообще!
PyImport_AddModule возвращает заимствованную ссылку. Это означает, что вам не разрешено Py_DECREF
вызывать Py_DECREF
если вы на самом деле не взяли на себя контроль над ним (например, увеличив счетчик ссылок через Py_INCREF
).
Python автоматически Py_Finalize
ссылки на модуль Py_Finalize
. Никаких дополнительных действий не требуется.
if (!r) {
PyErr_Print();
PyErr_Clear();
}
Py_Finalize()
ошибку и позволит вам успешно вызвать Py_Finalize()
.
PyErr_Print(0);
в строке после PyErr_Print();
? Если это не сработает, пожалуйста, отредактируйте свое сообщение, чтобы предоставить фактическую информацию о сбое.
Хорошо, я сам нашел ошибку. Вы можете вызывать только 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();