C++嵌入Python调用PyArray_SimpleNew触发段错误问题排查
问题描述
以下C++代码尝试嵌入Python调用NumPy C接口,提供普通版本与debug版本编译命令,运行时会在PyArray_SimpleNew函数调用处触发段错误,gdb调试无法获取有效定位线索:
// compile and link: // - regular: // g++ -std=c++11 -fPIC -I/usr/include/python3.10/ -I/usr/lib/python3/dist-packages/numpy/core/include/ -I.. ../sf.cpp -lpython3.10 // - debug: // g++ -g -std=c++11 -fPIC -I/usr/include/python3.10d/ -I/usr/lib/python3/dist-packages/numpy/core/include/ -I.. ../sf.cpp -lpython3.10d #include <Python.h> #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <numpy/ndarrayobject.h> int main() { auto* dims = new npy_intp[2]; dims[0] = 3; dims[1] = 4; PyObject* pyarray = PyArray_SimpleNew(2, dims, NPY_DOUBLE); }
问题根因
代码存在两个致命的初始化遗漏,直接导致段错误:
- 未初始化Python解释器:所有嵌入Python的C/C++程序,在调用任何Python C API之前,必须先调用
Py_Initialize()启动Python运行时环境,原代码完全跳过该步骤,Python内部状态未初始化就调用API会直接访问非法内存。 - 未初始化NumPy C API指针:调用任何NumPy提供的C接口之前,必须调用
import_array()宏。该宏负责加载NumPy模块、填充所有NumPy C函数的指针地址,跳过该步骤时PyArray_SimpleNew对应的函数指针是无效野指针,调用时会直接跳转到非法内存地址触发段错误。
另外原代码还存在资源泄漏问题:创建的NumPy数组对象、堆上分配的dims数组用完未释放,程序退出前也未调用Py_Finalize()销毁Python解释器。
修正后可运行代码
// compile and link: // - regular: // g++ -std=c++11 -fPIC -I/usr/include/python3.10/ -I/usr/lib/python3/dist-packages/numpy/core/include/ sf.cpp -lpython3.10 // - debug: // g++ -g -std=c++11 -fPIC -I/usr/include/python3.10d/ -I/usr/lib/python3/dist-packages/numpy/core/include/ sf.cpp -lpython3.10d #include <Python.h> #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <numpy/ndarrayobject.h> int main() { // 初始化Python解释器,必须在所有Python C API调用前执行 Py_Initialize(); // 初始化NumPy C API,必须在所有NumPy C API调用前执行 import_array(); npy_intp dims[2] = {3, 4}; PyObject* pyarray = PyArray_SimpleNew(2, dims, NPY_DOUBLE); // 释放资源 Py_XDECREF(pyarray); // 销毁Python解释器 Py_Finalize(); return 0; }
注意:debug版本编译时必须保证链接的python3.10d库和对应头文件版本完全匹配,不要混用release版和debug版的Python依赖,否则也可能出现难以定位的内存错误。
内容的提问来源于stack exchange,提问作者Joachim W
相关产品推荐
相关产品推荐

