malloc的每个现代实现都会在程序中引入UB吗?

时间:2016-10-17 21:04:07

标签: c language-lawyer

N1570closest 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编译器,我可以让它跟踪对reallocfree的调用,检查每个指针使用的指针列表已被释放,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第二次返回相同的指针并使程序做出奇怪的事情只是因为?

2 个答案:

答案 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,无论背后的簿记。