Python CFFI内存管理问题

时间:2016-03-29 20:25:34

标签: python-2.7 command-line ide glibc python-cffi

我正在使用Python 2.7.3在Ubuntu上编程。

我正在使用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 answer之后,我检查了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 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法:

我使用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。

答案 1 :(得分:0)

这可能也与Coverity在某些方面发现的这个错误有关 我们的CFFI生成的代码:

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

正如您所看到的,它在堆栈分配的内存上自由调用。