Проблемы управления памятью Python CFFI

Я программирую на Ubuntu, с Python 2.7.3,

Я использую CFFI для заполнения списка Python значениями, взятыми из некоторого C-кода.
Этот список довольно большой: около 71 000 символов при печати.

Код C использует много библиотек. Следовательно, следующий код предназначен только для лучшего понимания происходящего.

datas_list = []
for i in range( 0, x ):
    c_pDataStructure = ffi.new( "c_DataStructure[]", 1 )    // Create a pointer to the data structure
    c.SomeCFunction( c_pDataStructure )    // Populate the data structure
    datas_list.append( c.GetSomeInfo( c_pDataStructure ) )    // Get some info from the data structure
    c.FreeDataStructure( c_pDataStructure )    // Release dynamically allocated memory

Программа хорошо работает с использованием Wingware IDE, но заканчивается ошибкой glibc (*** glibc detected *** python: free(): invalid next size (fast): 0x0000000003b0b080 ***) при запуске из командной строки, прямо перед:

c_pDataStructure = ffi.new( "c_Datastructure[]", 1)  

Прочитав ответ wim, я проверил, выполняли ли код в IDE и командной строке один и тот же интерпретатор - они есть (/usr/bin/python).

РЕДАКТИРОВАТЬ (отчет Valgrind):

==5089== Process terminating with default action of signal 11 (SIGSEGV)  
==5089==  General Protection Fault  
==5089==    at 0x54FBB0: PyObject_Malloc (in /usr/bin/python2.7)  
==5089==    by 0x10B30625: allocate_owning_object (_cffi_backend.c:2972)  
==5089==    by 0x10B40EE8: allocate_with_allocator.constprop.84 (_cffi_backend.c:3032)  
==5089==    by 0x10B41010: direct_newp (_cffi_backend.c:3153)  
==5089==    by 0x10B4138C: b_newp (_cffi_backend.c:3177)  
==5089==    by 0x4F95A4: PyEval_EvalFrameEx (in /usr/bin/python2.7)  
==5089==    by 0x5008C1: PyEval_EvalCodeEx (in /usr/bin/python2.7)  
==5089==    by 0x4F9AB7: PyEval_EvalFrameEx (in /usr/bin/python2.7)  
==5089==    by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)  
==5089==    by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)  
==5089==    by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)  
==5089==    by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)

РЕДАКТИРОВАТЬ:
Вот еще немного информации о структуре данных C. Вот как это выглядит:

typedef struct _STRUCT3{
    some int, char*
}STRUCT3, *PSTRUCT3;

typedef struct _STRUCT2{
    some int
    PSTRUCT3 pStruct3;
}STRUCT3, *PSTRUCT3;

typedef struct _STRUCT1{
    some int, char*
    PSTRUCT2 pStruct2;
}STRUCT1, *PSTRUCT1;

Я сделал небольшую C-программу для выделения / освобождения полной C-структуры и valgrind не обнаружил утечки памяти.

Вопросы:

  • Что говорит выше valgrind отчет точно значит?
  • В чем могут быть различия между запуском программы из IDE и из командной строки?
    Примечание. В среде IDE используется аргумент Python. -u (unbuffered) запустить программу, но добавление ее в командную строку не имеет значения.
  • Когда я освобождаю структуру самостоятельно, работает ли сборщик мусора в Python? Должен ли я использовать ffi.gc( c_pDataStructure, c.FreeDataStructure ) вместо?

2 ответа

Решение

Я нашел, как исправить мои проблемы:

я использовал ffi.gc(cdata, destructor) создать структуру. Мой код Python теперь выглядит так:

data_list = []
for i in range( 0, x ):  
    # Create a pointer to the data structure and tell the garbage collector how to destroy it
    gc_c_pDataStructure = ffi.gc( c.CreateDataStructure(), c.FreeDataStructure )
    c.SomeCFunction( gc_c_pDataStructure )  # Populate the data structure
    datas_list.append( c.GetSomeInfo( gc_c_pDataStructure ) ) # Store some data  

Вот некоторые ссылки, связанные с ffi.gc():

А вот функция C для создания структуры данных (в соответствии с примером структуры из вопроса):

 PSTRUCT1 CreateDataStructure()
 {
     PSTRUCT1 pStruct1 = ( PSTRUCT1 ) malloc( sizeof( STRUCT1 ) );
     _SetDummyValues( pStruct1 );

     return pStruct1;
 }

Как видите, мне пришлось создать функцию void _SetDummyValues( PSTRUCT1 pStruct1 ), Эта функция устанавливает указанные указатели структуры в NULL.

Это также может быть связано с этой ошибкой, которую Coverity обнаружил в некоторых наших сгенерированных CFFI-кодах:

  x0 = (void *)alloca((size_t)datasize);
  ...
  { 
      free(x0); 
  }

Как вы можете видеть, он вызывается бесплатно в памяти, выделенной стеком.

Другие вопросы по тегам