Как устранить ошибку сегментации при работе с Python Ctypes и C ++?

Предположим, у меня есть следующие две сигнатуры функций в C ++:

BYTE* init( BYTE* Options, BYTE* Buffer ) 

а также:

 int next( BYTE* interface, BYTE* Buffer ) 

Идея состоит в том, что я сначала инициализирую класс Interface в C ++, а затем вызываю next функцию из Python со ссылкой на этот класс.

Первая функция возвращает указатель BYTE к интерфейсу через:

 Interface* interface; // initialize stuff return((BYTE*) interface); 

Я называю это в Python следующим образом:

 class Foo: def init(self, data): # left out: setting options_ptr buf = (c_ubyte * len(data.bytes)).from_buffer_copy(data.bytes) init_fun = getattr(self.dll, '?init@@YAPAEPAE0HH@Z') init_fun.restype = POINTER(c_ubyte) self.interface_ptr = init_fun(options_ptr, buf) # this works fine! def next(self, data): # create buf from other data buf = (c_ubyte * len(data.bytes)).from_buffer_copy(data.bytes) next_fun = getattr(self.dll, '?next@@YAHPAE0HN@Z') ret = next_fun(self.interface_ptr, buf) # I randomly get segmentation faults here 

Я называю это извне, например:

 foo = Foo() foo.init(some_data) foo.next(some_other_data) # ... foo.next(some_additional_data) 

Теперь, когда я запускаю его, я получаю ошибки сегментации:

 [1] 24712 segmentation fault python -u test.py 

Иногда это происходит после первого вызова .next() , иногда это происходит после одиннадцатого вызова .next() целиком в случайном порядке.

Существует тестовый код C ++ для API, который работает примерно так:

 BYTE Buffer[500000]; UTIN BufSize=0; BYTE* Interface; # not shown here: fill buffer with something Interface = init(Buffer); while(true) { # not shown here: fill buffer with other data int ret = next(Interface, Buffer); } 

Теперь, поскольку я не могу показать точный код, поскольку он намного больше и проприетарен, возникает вопрос: как я могу устранить такую ​​ошибку сегментации? Я могу ломаться, когда генерируется исключение (при отладке с VS2012), но он ломается здесь:

Ясно, что это не полезно, потому что ничего не делается с любым буфером в указанной строке. И значения переменных также являются загадочными:

В моем случае data являются объектами BitString . Может быть, проблема в том, что код C ++ выполняет операции с памятью в буфере? Или что некоторые данные собираются с помощью мусора Python, когда это все еще необходимо?

В более общем плане, как я могу обеспечить отсутствие ошибок сегментации при работе с Ctypes? Я знаю, что базовый DLL API работает отлично и не сбой.


Обновление: когда я делаю buf переменную экземпляра, например self._buf , я получаю ошибку сегментации, но во время отладки она ломается в другом месте:

One Solution collect form web for “Как устранить ошибку сегментации при работе с Python Ctypes и C ++?”

Было несколько недоразумений, которые я имел, и все это привело к проблемам:

  • Когда вы создаете объект Ctypes в Python и передаете его функции C, и что объект Python больше не нужен, он (вероятно) собирает мусор и больше не находится в стеке памяти, где C ожидает, что это будет.

    Поэтому сделайте буфер переменной экземпляра, например self._buf .

  • Функции C ожидают, что данные будут изменчивыми. Если функции C фактически не копируют данные где-то в другом месте, а работают непосредственно с буфером, это необходимо изменить. В документации Ctypes указано следующее:

    Присвоение нового значения экземплярам типов указателей c_char_p, c_wchar_p и c_void_p изменяет местоположение памяти, на которое они указывают, а не на содержимое блока памяти (конечно, нет, потому что строки Python неизменяемы).

    Однако вы должны быть осторожны, чтобы не передавать им функции, ожидающие указателей на изменяемую память. Если вам нужны измененные блоки памяти, ctypes имеет create_string_buffer() которая создает их различными способами. Текущее содержимое блока памяти может быть доступно (или изменено) с raw свойством; если вы хотите получить к нему доступ в виде строки с завершенным нулем, используйте свойство value :

    Итак, я сделал что-то вроде этого:

  self._buf = create_string_buffer(500000) self._buf.value = startdata.bytes 
  • Буфер должен использоваться в Python, как обычный массив, как показано в примере кода, где он заполняется, а данные внутри обрабатываются. Итак, для моего .next() я сделал следующее:
  self._buf.value = nextdata.bytes 

Теперь моя программа работает так, как ожидалось.

  • Как получить доступ с помощью ctypes к функциям, возвращающим пользовательские типы, закодированные в dll Delphi?
  • Ошибка ввода ключа ввода-вывода ввода-вывода
  • WindowsError: при загрузке DLL с помощью ctypes
  • Использование функции C в Python
  • Как использовать malloc и бесплатно с python ctypes?
  • Передача списка строк из python / ctypes в функцию C, ожидающую char **
  • Python: как увеличить экземпляр экземпляра POINTER
  • ctypes для статических библиотек?
  • Как преобразовать список Python в массив C с помощью ctypes?
  • Обтекание библиотеки C в Python: C, Cython или ctypes?
  • Что делает этот дескриптор безопасности плохим?
  •  
    Interesting Posts for Van-Lav
    Python - лучший язык программирования в мире.