包装 C++使用 Python+ctypes、段错误的动态数组
我想包装一段用 ctypes 分配数组的小型 C++ 代码,但将地址存储在 c_void_p 对象中时出现问题。
(注意:指针有意转换为 void*
,因为稍后我也想以相同的方式对 C++ 对象数组进行分配。)
要包装的 C(++) 函数:
void* test_alloc()
{
const int size = 100000000;
int* ptr = new int[size];
std::cout << "Allocated " << size * sizeof(int) << " bytes @ " <<
ptr << std::endl;
return static_cast<void*>(ptr);
}
void test_dealloc(void* ptr)
{
int* iptr = static_cast<int*>(ptr);
std::cout << "Trying to free array @ " << iptr << std::endl;
delete[] iptr;
}
Python 包装器(假设前面的函数已经使用 ctypes 导入):
class TestAlloc(object):
def __init__(self):
self.pointer = ctypes.c_void_p(test_alloc())
print "self.pointer points to ", hex(self.pointer.value)
def __del__(self):
test_dealloc(self.pointer)
对于小数组(例如 size = 10),看起来没问题:
In [5]: t = TestAlloc()
Allocated 40 bytes @ 0x1f20ef0
self.pointer points to 0x1f20ef0
In [6]: del t
Trying to free array @ 0x1f20ef0
但是如果我想分配一个大数组(size = 100 000 000),就会出现问题:
In [2]: t = TestAlloc()
Allocated 400000000 bytes @ 0x7faec3b71010
self.pointer points to 0xffffffffc3b71010L
In [3]: del t
Trying to free array @ 0xffffffffc3b71010
Segmentation fault
ctypes.c_void_p中存储的地址显然是错误的,高4字节无效。 不知何故,32 位和 64 位地址混合在一起,并且通过大型数组分配,内存管理器(在本例中)被迫返回无法在 32 位上表示的地址(thx TonJ)。
有人可以为此提供解决方法吗?
该代码已使用 g++ 4.4.3 编译,并在具有 4G RAM 的 Ubuntu Linux 10.04 x86_64 上运行。 Python版本是2.6.5。
非常感谢!
更新:
我设法解决了这个问题。我忘记为 test_alloc()
指定 restype。 restype 的默认值为 ctypes.c_int
,64 位地址不适合该值。通过在调用 test_alloc()
之前添加 test_alloc.restype = ctypes.c_void_p
解决了问题。
I wanted to wrap a small C++ code allocating an array with ctypes and there is something wrong with storing the address in a c_void_p object.
(Note: the pointers are intentionally cast to void*
, 'cause later I want to do the allocation the same way for arrays of C++ objects, too.)
The C(++) functions to be wrapped:
void* test_alloc()
{
const int size = 100000000;
int* ptr = new int[size];
std::cout << "Allocated " << size * sizeof(int) << " bytes @ " <<
ptr << std::endl;
return static_cast<void*>(ptr);
}
void test_dealloc(void* ptr)
{
int* iptr = static_cast<int*>(ptr);
std::cout << "Trying to free array @ " << iptr << std::endl;
delete[] iptr;
}
The Python wrapper (assume the former functions are already imported with ctypes):
class TestAlloc(object):
def __init__(self):
self.pointer = ctypes.c_void_p(test_alloc())
print "self.pointer points to ", hex(self.pointer.value)
def __del__(self):
test_dealloc(self.pointer)
For small arrays (e.g. size = 10), it seems ok:
In [5]: t = TestAlloc()
Allocated 40 bytes @ 0x1f20ef0
self.pointer points to 0x1f20ef0
In [6]: del t
Trying to free array @ 0x1f20ef0
But if I want to allocate a large one (size = 100 000 000), problems occur:
In [2]: t = TestAlloc()
Allocated 400000000 bytes @ 0x7faec3b71010
self.pointer points to 0xffffffffc3b71010L
In [3]: del t
Trying to free array @ 0xffffffffc3b71010
Segmentation fault
The address stored in ctypes.c_void_p is obviously wrong, the upper 4 bytes are invalid.
Somehow 32-bit and 64-bit addresses are mixed, and with the large array allocation the memory manager (in this case) is forced to return an address not representable on 32 bits (thx TonJ).
Can someone please provide a workaround for this?
The code has been compiled with g++ 4.4.3 and run on Ubuntu Linux 10.04 x86_64 with 4G RAM. Python version is 2.6.5.
Thank you very much!
UPDATE:
I managed to solve the problem. I forgot to specify restype for test_alloc()
. The default value for restype was ctypes.c_int
, into which the 64-bit address did not fit. By also adding a test_alloc.restype = ctypes.c_void_p
before the call of test_alloc()
solved the problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
仅从外观来看,问题似乎不在于小/大数组分配,而在于 32 位和 64 位地址的混合。
在您的示例中,小数组的地址适合 32 位,但大数组的地址不适合。
From just looking at it, it seems that the problem is not in the small/big array allocation, but in a mix of 32bit and 64bit addresses.
In your example, the address of the small array fits in 32 bits, but the address of the big array doesn't.