在 C 中对指向外部变量的指针调用 free

标签 c global-variables free allocation extern

我想知道 C 程序在指向外部变量的指针上调用 free 的行为。背景是我是一个分析 C 代码的验证器的开发人员,我想知道如果我的验证器遇到这种情况应该做什么(例如,说出为什么程序未定义 - 如果是)。

为了通过实验找出行为,我尝试运行以下 C 程序:

#include <stdlib.h>

extern int g = 1;

int main() {
    int *ptr = &g;
    free(ptr);
    return g;
}

在 Debian GNU/Linux 7 系统上,该程序崩溃并显示一条错误消息,指示传递给 free 的指针无效。在Windows 7系统上,我可以运行这个程序,没有任何错误消息。您知道对此观察结果的解释吗?

更新 我确实阅读了免费的定义。我的问题旨在这个定义是否实际上排除了这样的程序可以在符合标准的系统上可靠地工作的可能性(而不仅仅是“如果行为未定义,它可以做任何事情”)。所以我想知道您是否可以想到一个配置/系统/任何该程序不会公开未定义行为的地方。换句话说:是否存在根据 C 标准正确定义此处对 free 的调用的条件?

最佳答案

C 标准对此是明确的。引用文件N1570 ,最接近 C11 的近似值可在线免费获取,第 7.22.3.3 节第 2 段(free 的规范):

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

7.22.3开头列出了“内存管理函数”:malloc , calloc , realloc ,和aligned_alloc 。 (实现可以添加更多此类功能,例如 posix_memalign - 请阅读底部的注释!)

现在,“行为未定义”允许实现在这种情况发生时执行任何操作。崩溃很常见,但 MSVC 的运行时库完全有权检测指针位于“堆”之外并且不执行任何操作。尝试 Debug模式:可能有一种模式会导致程序崩溃。

作为代码验证工具的作者,应该尽可能严格:如果您无法证明传递给free的指针是 NULL或内存管理函数先前返回的值,将其标记为错误。

<小时/>

附录:有点令人困惑的“或者如果空间已被释放...”子句旨在禁止双重释放:

char *x = malloc(42);
free(x); // ok
free(x); // undefined behavior

...但要注意内存重用:

char *x = malloc(42);
uintptr_t a = (uintptr_t)x;
free(x);
x = malloc(42);
uintptr_t b = (uintptr_t)x;

observe(a == b); // un*specified* behavior - must be either true or false,
                 // but no guarantee which
free(x); // ok regardless of whether a == b
<小时/>

双附录:

Are there conditions under which the call to free here would be defined properly according to the C standard?

没有。如果存在这样的条件,则它必须出现在标准的文本中,作为我在本答案开头引用的规则的异常(exception),并且不存在任何此类异常(exception)。

但是,有一个微妙的变化,答案是"is":

Could there be an implementation of C under which the behavior of the program shown is always well-defined?

例如,一个实现,其中 free被记录为不执行任何操作,无论其输入如何,都符合条件,甚至不是一个疯狂的想法 - 许多程序可以从不调用 free , 毕竟。但根据 C 标准,程序的行为仍然是未定义的;只是 C 实现选择让这个特定的 UB 场景本身得到明确定义。

(从语言律师的角度来看,该语言的每个实现扩展都是一个明确定义 UB 场景的实现案例。甚至像 #include <unistd.h> 这样几乎无处不在的东西。)

关于在 C 中对指向外部变量的指针调用 free,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32995675/

相关文章:

c - 在 cygwin 中重新实现 mremap,新空间不可写

c - 输出中的 'y' 在 C 中代表什么?

javascript - 在单个 .js 文件中声明全局常量的安全问题

c - 后续函数调用中的 malloc

c - 在 C 中释放数组中结构体字段的内存

c - 替换C中字符串中的单词

c# - 在 ASP.NET 中使用 C# 全局变量的正确方法?

objective-c - 尝试访问应用程序委托(delegate)变量/属性

C:如何释放已分配字符串的初始部分?

c - 如何在 GDB 中定义 offsetof() 宏