c - `free(a_comparable_pointer)` 是定义明确还是 UB?

标签 c language-lawyer

当然,分配和释放同一个指针是明确定义的......

void *p1 = malloc(42);
assert(p1);
...
free(p1);

... 并通过 intptr_t/uintptr_t 转换创建一个 可比较 指针(如“比较等于”C11 7.20.1.4 中)当这些整数类型存在时,尽管不存在一定是相同的位模式。可以说 p2p3 具有相同的,但可能有不同的表示。

void *p2 = malloc(42);
assert(p2);
uintptr_t u2 = (uintptr_t) p2;
...
void *p3 = (void *) u2;

// Specified to evaluate true C11 7.20.1.4
if (p2 == p3) ...

// Maybe true, maybe false
if (memcmp(&p2, &p3, sizeof p2) == 0) ...

// Note - early version of post had this errant code
// if (memset(&p2, &p3, sizeof p2) == 0) ...

现在通过一个可比较指针到free()

The free function causes the space pointed to by ptr to be deallocated, ... if the argument does not match a pointer earlier returned by a memory management function ... behavior is undefined. C11dr §7.22.3.3 3

void *p4 = malloc(42);
assert(p4);
uintptr_t u4 = (uintptr_t) p4;
...
void *p5 = (void *) u4;
...
free(p5);  // UB or not UB?

所以标题问题似乎完成了:
关于 free(),“可比”是否足以“匹配”?

我怀疑 free(p5)undefined behavior (UB),但不确定。没有特定的应用程序 - 只是想了解 C 的角落,不要着急。

最佳答案

引用是 N1570 ,2011 年 ISO C 标准 (C11) 的最新公开草案。

void *p4 = malloc(42);
assert(p4);
uintptr_t u4 = (uintptr_t) p4;
...
void *p5 = (void *) u4;
...
free(p5);  // UB or not UB?

uintptr_t 的定义保证指针值p4p5 比较相等;更简洁地说,p4 == p5。从 6.5.9p6 中指针的 == 定义,我们知道 p4p5 指向同一个对象(因为我们已经已经确定 p3 的值不是空指针)。

这并不能保证它们具有相同的表示形式。该标准很少提及指针的表示形式(除了它们具有表示形式),因此 p4p5 完全有可能具有不同的表示形式。该标准在 6.2.6.1p4 中明确允许这样做:

Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations.

(这实际上可能会或可能不会,具体取决于实现情况。)

现在的问题是,到底传递给free的是什么?

函数调用在 6.5.2.2 中描述。第 4 段说:

In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument.

(强调已添加。)

所以 free() 看到的不是 p5 的对象表示(这可能与 p4 的对象表示不同),而是p5,保证与p4 的值相同。传递该值的机制可能涉及制作对象表示的副本,但所有标准都说该值已传递,并且 free 必须处理相同对象的任何不同表示以同样的方式值(value)。

关于c - `free(a_comparable_pointer)` 是定义明确还是 UB?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39582559/

相关文章:

c - posix_spawn OSX 错误信号陷阱

c++ - 关于如何在具有单个参数的变体构造中选择替代方案?

c++ - 将 operator new(sizeof(T) * N) 返回的内存视为数组

c++ - 是否在 C++ 中打印空字符串可观察行为?

c++ - 我可以隐式创建一个可简单复制的类型吗

c++ - 抑制 C++ 中未使用的变量警告 => 编译器错误或代码错误?

c - C 中的多行输入 - 疑难解答

c++ - `-fno-semantic-interposition` 与 `-fvisibility=protected` 究竟有何不同?

c - 在 linux C 中枚举目录条目时如何忽略子目录

c - 数据断点是如何创建的?