使用PyObject_Print触发Segmentation fault的原因及解决方法
问题描述
在CPython扩展代码中调用PyObject_Print打印PyObject时触发Segmentation fault,但通过PyObject_Repr结合PyUnicode_AsUTF8再使用printf却能正常运行。更换多个Python版本(3.7、Anaconda 3.11、mingw64 3.10.10)并使用VSCode调试后,问题依然存在。
测试代码
int main(){ Py_Initialize(); /////////////////////////////////////////// PyObject *tmp1 = PyLong_FromLong((1<<29)*3); PyObject *tmp2 = PyLong_FromLong((1<<20)*41+1264); PyObject *u; u = PyNumber_Multiply(tmp1,tmp2); PyObject_Print(u,stdout,Py_PRINT_RAW); // Segmentation fault here const char* uu = PyUnicode_AsUTF8(PyObject_Repr(u)); printf("%s\n", uu); // it works Py_Finalize(); return 0; }
编译配置(tasks.json)
{ "type": "cppbuild", "label": "C/C++: gcc.exe build active file", "command": "C:\\msys64\\mingw64\\bin\\gcc.exe", "args": [ "-fdiagnostics-color=always", "-g", "${file}", "-o", "${fileDirname}\\${fileBasenameNoExtension}.exe", "-I", "C:/Users/.../AppData/Local/Programs/Python/Python37/include", "-L", "C:/Users/.../AppData/Local/Programs/Python/Python37/libs", "-lpython37" ], "options": { "cwd": "${fileDirname}" }, "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true }, "detail": "Task generated by Debugger." }
不同版本错误细节:Python3.10.10调试时错误为Thread 1 received signal SIGSEGV, Segmentation fault. ntdll!TpWorkOnBehalfClearTicket () from C:\\WINDOWS\\SYSTEM32\\ntdll.dll,与Python3.7的错误细节不同。
解决方案
改用Python原生stdout对象:Windows环境下,mingw编译的C程序与MSVC编译的Python(如官方3.7版本)的
FILE*结构存在兼容性差异,直接传递C的stdout给PyObject_Print会导致段错误。替换为Python自身的sys.stdout对象:int main(){ Py_Initialize(); // 初始化并获取Python的sys.stdout PyObject *sys_module = PyImport_ImportModule("sys"); PyObject *stdout_obj = PyObject_GetAttrString(sys_module, "stdout"); PyObject *tmp1 = PyLong_FromLong((1<<29)*3); PyObject *tmp2 = PyLong_FromLong((1<<20)*41+1264); PyObject *u = PyNumber_Multiply(tmp1, tmp2); // 使用Python的stdout对象调用PyObject_Print PyObject_Print(u, stdout_obj, Py_PRINT_RAW); printf("\n"); // 手动换行,避免输出粘连 const char* uu = PyUnicode_AsUTF8(PyObject_Repr(u)); printf("%s\n", uu); // 释放引用计数 Py_DECREF(u); Py_DECREF(tmp1); Py_DECREF(tmp2); Py_DECREF(stdout_obj); Py_DECREF(sys_module); Py_Finalize(); return 0; }保持编译环境一致性:如果用mingw编译C代码,优先使用mingw编译的Python版本(如你尝试的3.10.10),避免混合MSVC和mingw编译的二进制文件,减少底层兼容性问题。
强制检查API返回值:虽然当前场景下
u有效,但养成检查每个Python API返回值的习惯能提前规避错误,比如:if (!tmp1 || !tmp2) { // 处理内存分配或对象创建失败 Py_Finalize(); return 1; } u = PyNumber_Multiply(tmp1, tmp2); if (!u) { // 处理乘法操作失败 Py_DECREF(tmp1); Py_DECREF(tmp2); Py_Finalize(); return 1; }
内容的提问来源于stack exchange,提问作者Jun Hong
相关产品推荐
相关产品推荐

