简体   繁体   English

使用Python + ctypes,segfault包装C ++动态数组

[英]Wrapping C++ dynamic array with Python+ctypes, segfault

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. 我想包装一个小的C ++代码,用ctypes分配一个数组,并且将地址存储在c_void_p对象中有问题。

(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.) (注意:有意地将指针强制转换为void* ,因为后来我也希望以相同的方式对C ++对象的数组进行分配。)

The C(++) functions to be wrapped: 要包装的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;
}

The Python wrapper (assume the former functions are already imported with ctypes): 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)

For small arrays (eg size = 10), it seems ok: 对于小数组(例如size = 10),似乎没问题:

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: 但是如果我想分配一个大的(大小= 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

The address stored in ctypes.c_void_p is obviously wrong, the upper 4 bytes are invalid. 存储在ctypes.c_void_p中的地址显然是错误的,高4字节无效。 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). 不知何故,32位和64位地址是混合的,并且在大数组分配的情况下,内存管理器(在这种情况下)被强制返回一个在32位(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. 该代码已使用g ++ 4.4.3编译,并在带有4G RAM的Ubuntu Linux 10.04 x86_64上运行。 Python version is 2.6.5. Python版本是2.6.5。

Thank you very much! 非常感谢你!

UPDATE: 更新:

I managed to solve the problem. 我设法解决了这个问题。 I forgot to specify restype for test_alloc() . 我忘了为test_alloc()指定restype。 The default value for restype was ctypes.c_int , into which the 64-bit address did not fit. restype的默认值是ctypes.c_int ,64位地址不适合。 By also adding a test_alloc.restype = ctypes.c_void_p before the call of test_alloc() solved the problem. 通过在调用test_alloc()之前添加test_alloc.restype = ctypes.c_void_p解决了问题。

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. 从它看来,似乎问题不在于小/大阵列分配,而是在32位和64位地址的混合中。 In your example, the address of the small array fits in 32 bits, but the address of the big array doesn't. 在您的示例中,小数组的地址适合32位,但大数组的地址不适合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM