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

Why doesn't the NumPy-C api warn me about failed allocations?

我一直在写一个 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)。 not surprising 这种大小的分配会失败,即使 Python 使用它的自定义分配器也是如此。真正让我担心的是 NumPy 没有引发错误或以其他方式表明数组创建没有按计划进行 .

我已经尝试在返回的数组上检查 PyArray_ISCONTIGUOUS,并使用 PyArray_GETCONTIGUOUS 确保它是单个内存段,但 segfault 仍然会出现。 NPY_ARRAY_DEFAULT 创建连续的数组,所以这无论如何都不是必需的。

我应该检查一些错误标志吗?我以后怎么能detect/prevent这种情况呢?BUFFER_LENGTH设置成一个较小的值显然是可行的,但是这个值是在运行时确定的,我想知道确切的范围。


编辑:

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

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

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

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

解决方法就是使用

output_buffer[buffer_len_alt - 1] = 'x'

(也就是说,我根本不明白你为什么需要演员表)。