最近code review的时候发现了一段magic code,free的指针指向了NULL,当时胆战心惊,第一反应就是free一个空指针会引起NE,应该和double free一个地址是同样的效果。但是冷静下来,想到这段代码是一段老code了,而且还在一直运行,应该没有问题才对,不然的话早就暴露出来了。
查到C标准库free有下面的描述。
**Description
The C library function void free(void ptr) deallocates the memory previously allocated by a call to calloc, malloc, or realloc.
Declaration
Following is the declaration for free() function.
void free(void ptr)
Parameters
ptr —— This is the pointer to a memory block previously allocated with malloc, calloc or realloc to be deallocated. If a null pointer is passed as argument, no action occurs.
Return Value
This function does not return any value.
如果free一个空指针,是没有任何事情发生的。和double free一个指针是不一样的。所以在申明一个指针的时候,最好赋初值NULL,例如char* str = NULL,后面不小心free了也没有问题发生。free一块malloc的指针后,需要将指针置为NULL,可以避免double free。原先以为free一块malloc的指针后将指针置为NULL是编码规则要求的,但是现在看是有着实际意义的。
现在维护的code中含有大量的下面类似的code。其实这种写法也不能避免double free,因为free之后没有将指针置为NULL。
if (pointer != NULL) {
free(pointer);
}
下面写法会更好
if (pointer != NULL) {
free(pointer);
pointer = NULL;
}
但是每次free之前还是都要判断pointer是否为NULL,感觉也不是很好,如果大家都养成free之后将pointer置为NULL并且声明定义指针赋初值NULL的习惯,那么判断条件是可以remove掉的。
{
free(pointer);
pointer = NULL;
}
下面写一个sample供大家参考。
typedef struct {
int id;
cahr* str;
} TestParam;
void testFree(int id) {
TestParam *testParam = NULL;
testParam = (TestParam*)malloc(sizeof(TestParam));
if (testParam == NULL) {
return;
}
memeset(testParam, 0, sizeof(TestParam));
testParam->id = id;
testParam->str = NULL;
// testParam->str 可能会在函数中某些地方通过malloc的方式赋值,也可能不会。
// 无论testParam->str是否通过malloc赋过值,都可以直接使用free函数,因为testParam->str初始值为NULL。当然条件是前面没有出现过free之后没有赋NULL的逻辑。
free(testParam->str);
testParam->str = NULL;
free(testParam);
testParam = NULL;
}
因为一个项目不会是一个人开发,知识准备可能不一样,我们只能严格要求自己了。free的时候需要判断是否是NULL,free之后置NULL。申明指针时初始值设为NULL。
所以最后一段code,一般会写成:
if(testParam != NULL) {
if (testParam->str != NULL) {
free(testParam->str);
testParam->str = NULL;
}
free(testParam);
testParam = NULL;
}
另外free的指针只限于malloc, calloc or realloc这三个分配后的内存指针。如果自己定义了一个局部指针
char str[] = “abcdef”;
如果free(str),我推测应该什么都不会做才对(undefined behavior occurs),和free(NULL)一样,大家可以做一下试验,毕竟结构和malloc的结构不一样,当然也要避免这种情况的发生。
free一块malloc的内存后,这块内存就是未知的,可能保持原来的值,也可能已经被分配了,这时候再次free就会导致严重问题了(undefined behavior occurs)。
编程真是学无止境,只能靠一点一点积累和保持一颗好奇和学习的心了。越是认为简单的东西,包含的知识越是丰富。