【问题标题】:Why doesn't the NumPy-C api warn me about failed allocations?为什么 NumPy-C api 不警告我分配失败?
【发布时间】:2016-09-08 08:47:19
【问题描述】:

我一直在编写一个 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 创建了连续的数组,所以无论如何都不需要这样做。

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


编辑:

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

【问题讨论】:

  • 这是否与转换为 int (((int) buffer_len_alt) - 1) 的转换有关,它可能已签名,但无法保持 BUFFER_LENGTH? (假设 32 位整数)
  • @DavidW 你应该这样回答。 buffer_len_alt 的类型为 npy_intp,在大多数平台上是一个 64 位有符号整数。如果平台上的int类型为32位,那么buffer_len_alt为3*(2**30)时(int) buffer_len_alt为负整数。
  • @DavidW 感谢您的建议!我能够确认这确实是问题所在。如果您发布答案,我一定会将其标记为已接受。

标签: python c numpy python-c-api


【解决方案1】:

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

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

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

解决办法就是使用

output_buffer[buffer_len_alt - 1] = 'x'

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 2018-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多