为什么NumPy-C api没有警告我分配失败?

时间:2016-09-08 08:47:20

标签: python c numpy python-c-api

我一直在编写一个Python扩展,从C写入NumPy数组。在测试过程中,我注意到某些非常大的数组会在我尝试访问某些数组时产生segfault元素。

具体来说,以下代码段的最后一行失败,并带有segfault

    // Size of buffer we will write to
    npy_intp buffer_len_alt = BUFFER_LENGTH;

    //
    PyArray_Descr * dtype;
    dtype = PyArray_DescrFromType(NPY_BYTE);
    PyObject* column = PyArray_Zeros(1, &buffer_len_alt, dtype, 0);

    //Check that array creation succeeds
    if (column == NULL){
        // This exit point is not reached, so it looks like everything is OK
        return (PyObject *) NULL;
    }

    // Get the array's internal buffer so we can write to it
    output_buffer = PyArray_BYTES((PyArrayObject *)column);

    // Try writing to the buffer
    output_buffer[0] = 'x'; //No segfault
    output_buffer[((int) buffer_len_alt) - 1] = 'x'; // Segfault here

我检查过,发现只有当我尝试分配大约3GB的数组时才会发生错误(即BUFFER_LENGTH约为3 * 2 ^ 30)。即使Python使用它的自定义分配器,这个大小的分配也会失败,这是not surprising。我真正关心的是NumPy 没有引发错误或以其他方式表明数组创建没有按计划进行

我已经尝试在返回的数组上检查PyArray_ISCONTIGUOUS,并使用PyArray_GETCONTIGUOUS确保它是单个内存段,但仍会出现segfaultNPY_ARRAY_DEFAULT创建了连续的数组,因此无论如何都不需要这样做。

我应该检查一些错误标志吗?如何在将来检测/防止这种情况?BUFFER_LENGTH设置为较小的值显然有效,但此值在运行时确定,我想知道确切的界限。

修改

正如@DavidW指出的那样,错误源于将buffer_len_alt转换为int,因为npy_intp可以是64位数字。将强制转换替换为int并使用强制转换为'unsigned long'可以解决问题。

1 个答案:

答案 0 :(得分:2)

问题(在评论中诊断)实际上是使用数组查找而不是数组的分配。您的代码包含

output_buffer[((int) buffer_len_alt) - 1] = 'x'

buffer_len_alt(约值3000000000)被转换为(32位)int(最大值2147483647)时,您的地址无效,可能是一个较大的负数。

解决方案就是使用

output_buffer[buffer_len_alt - 1] = 'x'

(即我不明白为什么你需要演员)。