Numpy C++ 程序总是给出段错误(很可能滥用语法或类型)

Posted

技术标签:

【中文标题】Numpy C++ 程序总是给出段错误(很可能滥用语法或类型)【英文标题】:Numpy C++ program always gives segfault (most likely misuse of syntax or types) 【发布时间】:2013-09-12 18:00:57 【问题描述】:

我正在为 python 程序开发我的第一个 C++ 扩展。我已经尝试调试这段特定的代码几个小时了,但我没有想法。

段错误似乎与传递给 C++ 代码的 PyArrayObject old_simplices_array 有关。该对象是 2d numpy array 类型的 uint32

此代码是直接根据scipy.weave 组合而成的。当代码为 scipy.weave.inline 格式化和使用时,一切正常。这似乎消除了我程序的 python 部分和算法本身成为可能的罪魁祸首。

剩下的只是语法和类型。有没有人看到任何不正确的语法或类型转换代码?

static PyObject* exterior(PyObject* self,
                          PyArrayObject* old_simplices_array)

    const short unsigned int step = old_simplices_array->dimensions[1];
    const short unsigned int j_max = step - 1;
    const long unsigned int col_max = 
        old_simplices_array->dimensions[0] * step;
    short unsigned int j, k, face_index;
    long unsigned int col;
    unsigned int num_simplices = 0;

    PyObject* indices = PyList_New(0);
    PyObject* indptr =  PyList_New(0);
    PyObject* data =  PyList_New(0);
    PyObject* simplices = PyList_New(0);
    PyList_Append(indptr, PyLong_FromLong(0));
    PyObject* simplex_to_index = PyDict_New();

    for(col = 0; col < col_max; col+=step)
    
        for(j = 0; j <= j_max; j++)
        
            face_index = 0;
            PyObject* face = PyTuple_New(j_max);
            for(k = 0; k <= j_max; k++)
            
                if(j != k)
                
                    PyTuple_SetItem(face, face_index, 
                        PyLong_FromLong(old_simplices_array->data[col + k]));
                    face_index++;
                
            

            if(PyDict_Contains(simplex_to_index, face))
            
                PyList_Append(indices, 
                    PyDict_GetItem(simplex_to_index, face));
            
            else
            
                PyDict_SetItem(simplex_to_index, face, 
                    PyLong_FromLong(num_simplices));
                PyList_Append(simplices, face);
                num_simplices++;
            
            PyList_Append(data, PyLong_FromLong(1 - 2 * (j % 2)));
        
        PyList_Append(indptr, PyLong_FromLong(col + j));
    
    return PyTuple_Pack(3, PyTuple_Pack(3, data, indices, indptr), simplices,
        simplex_to_index);
                                

-----更新------

gdb 表示

const short unsigned int step = old_simplices_array->dimensions[1];

导致段错误。我是否误用了类型?

-----更新------

尽管 GDB 告诉我,

const short unsigned int step = old_simplices_array-&gt;dimensions[1];

导致segfault,如果我在for循环之前从程序返回,我没有segfault(只是python端的错误抱怨返回NoneType)。

这是完整的回溯:

Program received signal SIGSEGV, Segmentation fault.
exterior (self=<optimized out>, old_simplices_array=0xec0a50)
    at src/_alto.cpp:39
warning: Source file is more recent than executable.
39      const short unsigned int step = old_simplices_array->dimensions[1];
(gdb) bt
exterior (self=<optimized out>, old_simplices_array=0xec0a50)
    at src/_alto.cpp:39
0x00007ffff7aedad2 in PyEval_EvalFrameEx ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7aeddc9 in PyEval_EvalFrameEx ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7aee902 in PyEval_EvalCodeEx ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7a70ad6 in ?? ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7a4565e in PyObject_Call ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7a53b80 in ?? ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7a4565e in PyObject_Call ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7aaaea0 in ?? ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7aa68bc in ?? ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7a4565e in PyObject_Call ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7ae9bce in PyEval_EvalFrameEx ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7aee902 in PyEval_EvalCodeEx ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7aeea32 in PyEval_EvalCode ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7b103fa in PyRun_FileExFlags ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7b10e3d in PyRun_SimpleFileExFlags ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff7b26972 in Py_Main ()
   from /usr/lib/sagemath/local/lib/libpython2.7.so.1.0
0x00007ffff6d29ea5 in __libc_start_main ()
   from /lib/x86_64-linux-gnu/libc.so.6
0x00000000004006d1 in _start ()

【问题讨论】:

您是否尝试过使用调试器?你在哪一行有段错误? @hidrargyro 感谢您的建议。这让我想到了第一行: const short unsigned int step = old_simplices_array->dimensions[1]; @Feynman 根据文档,看起来PyArrayObject.nd 告诉你传入的维度数组有多大。你能assert(old_simplices_array-&gt;nd &gt;= 2); 不会失败吗? 尝试打印 old_simplices_array->dimensions 值,仅用于检查对象的完整性 我几乎可以肯定您的问题来自您访问old_simplices_array-&gt;data 的方式。你的数组是连续的吗?它是什么数据类型? 【参考方案1】:

通常,C 模块中方法的签名是PyObject* f(PyObject* self, PyObject* args),其中args 旨在由PyArg_ParseTuple 解析。您可以在代码scipy.weave 生成:http://docs.scipy.org/doc/scipy/reference/tutorial/weave.html#a-quick-look-at-the-code) 中看到这一点。除非有一些您尚未发布的包装函数为您调用PyArg_ParseTuple,否则您的exterior 方法必须调用它以从通用PyObject* args 中提取PyArrayObject

【讨论】:

以上是关于Numpy C++ 程序总是给出段错误(很可能滥用语法或类型)的主要内容,如果未能解决你的问题,请参考以下文章

Numpy C++:如何在没有段错误的情况下迭代 PyArrayObject

构建 Numpy C++ 扩展;调用 PyArray_FROM_OTF 时出现段错误

Numpy C API - 使用 PyArray_Descr 创建数组会导致段错误

JSP 调试

段错误的最小 C/C++ 程序? [复制]

如果给出错误的参数,则中止程序,C++ [重复]