Обтекание динамического массива C ++ Python + ctypes, segfault - PullRequest
4 голосов
/ 23 июня 2010

Я хотел обернуть небольшой код C ++, выделяя массив с ctypes, и что-то не так с сохранением адреса в объекте 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

Но если я хочу выделитьбольшой (размер = 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 и запущен на Ubuntu Linux 10.04 x86_64 с 4G RAM.Версия Python 2.6.5.

Большое спасибо!

ОБНОВЛЕНИЕ:

Мне удалось решить проблему.Я забыл указать restype для test_alloc().Значение по умолчанию для restype было ctypes.c_int, в которое не помещался 64-битный адрес.Также добавление test_alloc.restype = ctypes.c_void_p перед вызовом test_alloc() решило проблему.

1 Ответ

1 голос
/ 23 июня 2010

Если посмотреть на это просто, то кажется, что проблема не в распределении большого / малого массива, а в сочетании 32-битных и 64-битных адресов. В вашем примере адрес небольшого массива умещается в 32 бита, а адрес большого массива - нет.

...