我一直在编写一个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
确保它是单个内存段,但仍会出现segfault
。 NPY_ARRAY_DEFAULT
创建了连续的数组,因此无论如何都不需要这样做。
我应该检查一些错误标志吗?如何在将来检测/防止这种情况?将BUFFER_LENGTH
设置为较小的值显然有效,但此值在运行时确定,我想知道确切的界限。
修改:
正如@DavidW指出的那样,错误源于将buffer_len_alt
转换为int
,因为npy_intp
可以是64位数字。将强制转换替换为int
并使用强制转换为'unsigned long'可以解决问题。
答案 0 :(得分:2)
问题(在评论中诊断)实际上是使用数组查找而不是数组的分配。您的代码包含
行output_buffer[((int) buffer_len_alt) - 1] = 'x'
当buffer_len_alt
(约值3000000000)被转换为(32位)int(最大值2147483647)时,您的地址无效,可能是一个较大的负数。
解决方案就是使用
output_buffer[buffer_len_alt - 1] = 'x'
(即我不明白为什么你需要演员)。