为什么我没有得到细分错误?

时间:2019-01-07 06:25:44

标签: c malloc dynamic-memory-allocation

我有

x=(int *)malloc(sizeof(int)*(1));

但我仍然可以阅读x[20]x[4]

如何访问这些值?访问这些内存时我应该不会出现分段错误?

2 个答案:

答案 0 :(得分:1)

Sourav Ghosh的基本前提是:从malloc返回的超出您要求的大小的内存是未定义的行为,因此允许遵循的实现几乎可以做任何事情,包括愉快地返回奇怪的值。

但是,鉴于在“普通”计算机(gcc / MSVC / clang,Linux / Windows / macOS,x86 / ARM)上的主流操作系统上实现了“普通”实施,为什么有时会出现分段错误(或访问冲突),并且有时不是吗?

在通过指针读取/写入时,几乎所有“常规” C实现都不会执行任何类型的内存检查。这些加载/存储通常直接转换为相应的机器代码,该机器代码在给定位置访问内存,而无需过多考虑“抽象C机器”对象的大小。

但是,在这些机器上,CPU不能直接访问PC的物理内存(RAM),而是引入了转换层(MMU) 2 ;每当您的程序尝试访问地址时,MMU都会检查是否已在此映射任何内容,以及您的进程是否有权在此处进行写操作。如果这些检查中的任何一个未通过 3 ,您就会遇到分段错误,并且您的进程将被杀死。这就是为什么未初始化的指针值和NULL指针值通常会产生良好的段错误的原因:虚拟地址空间开头的一些内存未映射就保留了,只是为了发现NULL取消引用,并且通常情况下,如果您随机地掷镖在32位地址空间(甚至更好的是64位地址空间)中,您最有可能找到从未映射到任何内容的内存区域。

尽管如此,由于多种原因,MMU无法捕获所有内存错误。

首先,与大多数“磨合”分配相比,内存映射的粒度相当粗糙。在PC上,内存页(可以映射并具有保护属性的最小内存单元)的大小通常为4 KB。当然,这里需要权衡:非常小的页面本身将需要大量内存(因为有目标物理地址以及与每个页面相关联的保护属性,并且这些属性必须存储在某个地方),并且会减慢MMU操作的速度。 3 。因此,如果您访问内存超出“逻辑”范围,但仍在同一内存页面内,则MMU无法帮助您:就硬件而言,您仍在访问有效内存。

此外,即使您不在分配的最后一页之外,就硬件而言,下一页也可能是“有效”的;实际上,这对于从所谓的堆(malloc和朋友)获得的内存来说非常普遍。

这是由于以下事实:对于较小的分配,malloc不会要求操作系统提供“新的”内存块(从理论上讲,可以在内存两端分配保护页);取而代之的是,C运行时中的分配器以较大的顺序块向操作系统请求内存,并在逻辑上将它们划分为较小的区域(通常保存在某种类型的链接列表中),这些区域在malloc上分发并由free

现在,当您在程序中跨出请求的内存边界时,可能不会出现任何错误,如下所示:

  • 您使用的内存块不在页面边界附近,因此您的越界读取不会触发访问冲突;
  • 即使它位于页面的末尾,由于其仍属于堆,因此其后的页面仍被映射。它可能是已分配给进程其他代码的内存(因此,您正在读取代码中某些不相关的部分的数据),或者是空闲内存区域(因此,您正在读取上一代码中可能留下的任何垃圾) free时,该块的所有者),或分配器用来保留其预订数据的区域(因此您正在读取此类数据的一部分)。

    在所有这些情况下,除了“空闲块”之外,即使您在那写,也不会遇到分段错误,但是您可能会破坏不相关的数据或堆的数据结构(通常会导致稍后崩溃,因为分配器发现其数据不一致。


注释

  1. 尽管现代编译器提供了特殊的工具化版本来捕获其中的一些错误;尤其是gcc和clang提供了所谓的“地址清理器”。
  2. 这允许引入透明的分页(交换到物理内存可用性低的情况下不主动使用的磁盘存储区域),最重要的是,引入内存保护和地址空间分离(在运行用户模式进程时) ,它“看到”了一个完整的虚拟地址空间,只包含他的东西,而没有其他进程或内核的东西。
  3. 通知操作系统进程正在尝试访问已换出的内存,这并不是操作系统故意造成的。
  4. 鉴于每次对内存的访问都需要通过MMU,因此映射必须非常快,因此将最常用的页面映射保存在缓存中;如果您将页面设置得很小,并且缓存可以容纳同样多的条目,那么实际上,缓存可以覆盖较小的内存范围。

答案 1 :(得分:0)

否,访问无效内存是undefined behaviorsegmantation fault是UB的许多副作用之一。不保证。

那是

  • 在使用返回的指针之前,始终通过针对malloc()检查返回的指针来检查NULL是否成功。
  • 请参阅以下内容:Do I cast the result of malloc?