c-malloc如何处理严格的别名?它只能在一个编译单元内被违反吗



看完这篇文章后,我有一个类似的问题,想知道内存分配器如何在不违反严格的别名规则的情况下工作。但我并不想知道如何重新使用释放的内存,我想知道如何在不违反严格别名的情况下将分配的对象定位在线性内存中。

到目前为止,我所研究的所有堆内存分配器都将它们的内存划分为某种块,前面有一个标头。然而,malloc返回一个void *,并且通常指向头之后的内存。下面是一个非常缩小的例子来说明这一点。

#include <stddef.h>
struct block_header {
size_t size;
};
struct block_header *request_space(size_t size);
void *malloc(size_t size) {
struct block_header *block = request_space(size);
// I guess this violates strict aliasing, because the caller will 
// convert the pointer to something other than struct block_header?
// Or why wouldn't it?
return block + 1;
}

我已经研究了一段时间,但我看不出分配器如何在不违反严格别名的情况下将指针定位在内存区域中。我错过了什么?

根据标准,这些东西从不违反严格的别名:

  • 投射指针
  • 正在进行指针运算
  • 写入malloc空间

在malloc'd空间中不允许做的事情是将一些内存读取为与写入时不同的类型(当然,允许的别名类型列表除外(。

规则文本在C11 6.5/7:中

对象的存储值只能由[…]访问

6.5/6中的文本解释说,如果我们在malloc'd空间中,那么写操作会将写操作的类型压印到目标上(因此不可能存在类型不匹配(。

到目前为止,你发布的代码从未做过被禁止的事情,所以没有明显的问题。只有当有人使用了您的分配器,然后读取内存而不写入内存时,才会出现问题。

脚注1:6.5/6根据委员会对DR236的回应显然有缺陷,但从未修复,所以谁知道这会给我们带来什么。

脚注2:正如Eric所指出的,该标准不适用于实现内部,但请考虑我在一些用户编写的分配器的上下文中的评论,就像在您链接的另一个问题中一样。

malloc的源代码不需要像普通源代码那样符合C标准。它是C实现的一部分。

malloc、编译器和C实现的其他部分的工作人员负责确保它们协同工作。这可以包括编译器使用C编译器而不是C标准所保证的行为来专门处理mallocmalloc

C标准有意避免要求所有实现都适用于所有目的。相反,它被设计为允许用于各种目的的实现,作为"一致性语言扩展"的一种形式,以对这些目的有用的方式有意义地处理构造,即使标准没有提出任何要求。因此,该标准允许用于需要手动内存管理的任务的实现支持促进此类任务的"流行扩展",尽管它有意避免非用于此类任务的实现需要此类支持。

许多类型的内存分配器在语义仅限于标准规定的实现上是不切实际的。然而,坚持委员会所描述的"不要阻止程序员做需要做的事情"的C原则的实现,并且被设计和配置为适合构建这样的分配器,将认识到存储将被用作多种类型的指示。编纂者承认此类指示的确切情况范围是标准管辖范围之外的"实施质量"问题。从实用的角度来看,clang和gcc的作者选择了以最低允许质量的方式行事,除非使用-fno-strict-aliasing,但这意味着想要对这些编译器做任何"有趣"的事情的程序员必须使用该选项。没有任何证据表明该标准的作者打算让程序员跳过重重关卡来适应低质量实现的限制;相反,他们预计市场将比委员会更适合判断编纂者在完成各种任务时应该如何最有效地行事。

相关内容

最新更新