我知道这是一个老问题,但在C语言中几乎任何事情都是可能的。虽然已经有一些hackish解决方案了,但判断内存是否被正确分配的有效方法是使用预测器来代替malloc
、calloc
、realloc
和free
。这跟测试框架(如cmocka)检测内存问题(如段错误、未释放内存等)的方式相同。你可以在分配内存时维护一个内存地址列表,并在用户想要使用你的函数时简单地检查这个列表。我为自己的测试框架实现了非常类似的东西。下面是一些示例代码:
typedef struct memory_ref {
void *ptr;
int bytes;
memory_ref *next;
}
memory_ref *HEAD = NULL;
void *__wrap_malloc(size_t bytes) {
if(HEAD == NULL) {
HEAD = __real_malloc(sizeof(memory_ref));
}
void *tmpPtr = __real_malloc(bytes);
memory_ref *previousRef = HEAD;
memory_ref *currentRef = HEAD->next;
while(current != NULL) {
previousRef = currentRef;
currentRef = currentRef->next;
}
memory_ref *newRef = (memory_ref *)__real_malloc(sizeof(memory_ref));
*newRef = (memory_ref){
.ptr = tmpPtr,
.bytes = bytes,
.next = NULL
};
previousRef->next = newRef;
return tmpPtr;
}
您需要为
calloc
、
realloc
和
free
编写类似的函数,每个包装器都以
__wrap_
为前缀。真正的
malloc
可通过使用
__real_malloc
获得(对于您要包装的其他函数也是如此)。每当您想要检查内存是否实际分配时,只需遍历链接的
memory_ref
列表并查找内存地址。如果您找到它并且它足够大,则可以确定该内存地址不会使程序崩溃;否则返回错误。在程序使用的头文件中,您将添加以下行:
extern void *__real_malloc (size_t);
extern void *__wrap_malloc (size_t);
extern void *__real_realloc (size_t);
extern void *__wrap_realloc (size_t);
// Declare all the other functions that will be wrapped...
我的需求相当简单,所以我实现了一个非常基本的版本,但你可以想象如何扩展它以拥有更好的跟踪系统(例如,创建一个
struct
除了大小外还跟踪内存位置)。然后,您只需要使用编译器编译代码。
gcc src_files -o dest_file -Wl,-wrap,malloc -Wl,-wrap,calloc -Wl,-wrap,realloc -Wl,-wrap,free
缺点是用户必须使用上述指令编译他们的源代码,但这远非我所见过的最糟糕的情况。在分配和释放内存时存在一些开销,但添加安全性时总会存在一些开销。