N1570(closest draft to the C11 standard)声明:
J.2未定义的行为
1在以下情况下,行为未定:
[剪断]
- 使用引用通过调用free或realloc函数释放的空间的指针的值(7.22.3)。
请注意,这表示"使用",而不是" dereferenced",这有一些严重的影响。根据我的阅读,这是UB:
void* foo = malloc(4);
free(foo);
printf("%p\n", foo); // UB!
事实上,无论foo
的价值如何,它现在似乎都被永久污染了。
当然,编译器不需要在这里执行任何类型的执行(因为"它只是工作"是有效的未定义行为),我的意见是这里的任何类型的执行只会旅行诚实的开发人员(除非你在一个只加载无效地址导致问题的平台上......)。
然而,在我看来,如果我想编写一个病态的C编译器,我可以让它跟踪对realloc
和free
的调用,检查每个指针使用的指针列表已被释放,make demons come out of the user's nose如果找到匹配的那个。
有趣的是,每个现代malloc
实现都会很乐意重用之前已经释放的分配:
void* foo = malloc(4);
free(foo);
foo = malloc(4); // potentially the same address as the previous allocation
是否允许由具有最恶意读取标准的作者编写的病态C编译器检查malloc
第二次返回相同的指针并使程序做出奇怪的事情只是因为?
答案 0 :(得分:4)
这是否意味着他们都将UB引入C程序?
malloc重新使用以前释放的内存块不会自动引入UB
使用引用空格解除分配的指针
旧指针的使用(因而假设它背后是旧数据或结构) - 是UB
示例:
char * p1 = malloc(...);
free(p1);
double * p2 = malloc(...);
// lets assume p2 == p1 (ie malloc implementation re-used address)
// here you can use p2 without any problems or UB
// BUT, usage of P1 here is UB
free(p2);
// usage of P1 and P2 is UB here
答案 1 :(得分:4)
有趣的是,每个现代malloc实现都会很乐意重用之前已经释放的分配。这是否意味着他们都将UB引入C程序?
没有。
问题不在于malloc
是否在不同的调用中返回相同的值,问题是指针值在表达式中使用时是否为有效。
您可以在不调用UB的情况下为现有指针对象分配新值(有效或其他)。调用UB的是尝试在表达式中使用无效指针值,无论是取消引用指针,还是执行指针算法等。
T *ptr = malloc( sizeof *ptr * N );
...
free( ptr );
此时,ptr
中包含的值无效(指针值不再与程序中的对象关联)。此时使用ptr
的值(通过取消引用它,或通过对它进行指针运算等)调用UB。但是,如果你这样做
ptr = malloc( sizeof *ptr * N );
再次,并且第二次获得相同的指针值,然后该值再次有效 - 该指针值已与程序中的对象重新关联。
如果malloc
/ calloc
/ realloc
返回的值不是NULL
,则它是一个有效的指针值,使用它不会调用UB,无论背后的簿记。