Python: ctypes + C malloc 错误。是 C 内存问题还是 Python/ctypes 问题?

2 投票
1 回答
3834 浏览
提问于 2025-04-16 18:55

大家好。我在使用ctypes和C代码时遇到了内存分配错误。我在想这个内存问题是出在C代码里,还是因为我不正确地使用了ctypes。这个内存错误的提示是:

python(79698) malloc: * 对象 0x15627ac08 的错误:释放的对象校验和不正确 >- 这个对象可能在被释放后被修改了。 * 在malloc_error_break处设置断点以调试 中止

或者

python(76110,0x7fff70062ca0) malloc: * 对象 0x7d807e1078907df 的错误:被释放的指针没有被分配 * 在malloc_error_break处设置断点以调试 中止

这取决于我下面“free_some_memory”部分的代码怎么写。我不会在这里贴一大堆C代码,但假设我的C代码是正确的,我的ctypes接口看起来对吗?

另外,我遇到的错误并不总是在我的脚本中同一个地方发生,对于同一个版本的“free_some_memory”。我的C代码的内存管理写得很糟糕,可能导致Python的内存管理出错,搞乱了(重新)分配吗?

不知道这是否重要,但我是在Mac上工作,系统是Snow Leopard。
任何帮助都将非常感谢。

最好的祝愿,
jkmacc

我的C代码看起来是这样的:

/**** cfunction.c ****/
int cfun (double *y, char datafile[1024], int byteoffset, int num )
{
  allocate_some_memory;
  do_stuff;

  if ( error_condition )
  {
    free_some_memory;
    return ( -1 );
  }

  fill_y_here;
  free_some_memory;
  return ( 0 );
}

我的ctypes包装器看起来是这样的:

#pyfunction.py

import ctypes as C
import numpy as np

lib = C.CDLL('mylib.dylib')

def pyfun(DATAFILE, BYTEOFFSET, NUM):
    """
    DATAFILE: a string file name
    BYTEOFFSET: an integer
    NUM: an integer
    """

    #return integer success/failure flag
    lib.cfun.restype = C.c_int 

    #array memory to be filled inside of C
    Y = np.empty(NUM,dtype='double',order='C')

    cDATAFILE = C.create_string_buffer(DATAFILE,1024) 
    cBYTEOFFSET = C.c_int(int(BYTEOFFSET))
    cNUM = C.c_int(int(NUM))

    flag = lib.cfun(Y.ctypes.data_as(C.POINTER(C.c_double)), \ 
               cDATAFILE,cBYTEOFFSET,cNUM)

    if flag == -1:
        print("Something went wrong.")
        return -1
    else:
        return Y

1 个回答

4

我遇到了这个问题,下面是我总结的经验:

如果你用ctypes映射了一些东西,然后又释放了它,当这个ctypes对象被销毁时就会出现错误。所以,在你调用free()之前,必须确保在Python代码中没有对它的引用。

所以,你的C代码应该是这样的:

char* p;
char* allocate() {
 p = asprintf("hello world");
 return(p)
}
void freep() {
 free(p);
}

而你的Python代码应该是这样的:

allocate = clib.allocate
allocate.restype = c_char_p()
p = allocate()
print p
# This is the key:
del(p)
clib.freep()

如果你想看到错误,只需省略del(p)这行代码。

撰写回答