【问题标题】:Can a C/C++ program seg-fault from reading past the end of an array (UNIX)?C/C++ 程序可以读取超出数组末尾的段错误(UNIX)吗?
【发布时间】:2023-03-22 20:26:01
【问题描述】:

我知道您可以读取超出数组末尾的内容 - 我现在想知道您是否可以通过执行该读取操作来进行 seg-fault。

int someints[100];
std::cerr << someints[100] << std::endl; //This is 1 past the end of the array.

第二行真的会导致段错误还是只会打印乱码?另外,如果我更改了该内存,是否会导致在该特定行上出现段错误,或者仅当其他东西试图使用意外更改的内存时才会发生错误?

【问题讨论】:

  • 它更有可能打印乱码而不是核心转储,但行为是未定义的,它可以简单地重新格式化整个磁盘(并且没有理由抱怨 - 你调用了未定义的行为)。不要尝试。绝对不要依赖轻度虐待;你不知道哪个变量被写入了。

标签: c++ c unix


【解决方案1】:

这是未定义的行为,完全取决于操作系统为进程安排的虚拟内存布局。通常您可以:

  • 访问一些属于您的虚拟地址空间但具有无意义值的乱码,或者
  • 尝试访问受限制的内存地址,在这种情况下,内存映射硬件会调用页面错误,并且操作系统会决定是对您的进程进行打击还是分配更多内存。

如果someints 是堆栈上的一个数组并且是声明的最后一个变量,那么您很可能会从堆栈顶部得到一些乱码,或者(非常不可能)调用可能让操作系统调整大小的页面错误使用SIGSEGV 堆栈或终止您的进程。

假设您在数组之后声明了一个 int

int someints[100];
int on_top_of_stack = 42;
std::cerr << someints[100] << std::endl;

那么程序很可能应该打印42,除非编译器以某种方式重新排列堆栈上的声明顺序。

【讨论】:

  • 我的系统上只有 42 个,但没有特别的理由期望 on_top_of_stack 将在 someints 之后立即分配。例如,如果小偏移量更便宜,则可能有充分的理由将较小的对象放在堆栈帧的开头。
  • 如果你打开优化器,所有的赌注都会被关闭。声明的顺序与内存中的顺序无关,结构中的字段除外。
  • @Keith 和 Dietrich:这就是为什么我说“最有可能”而不是“总是”。
  • @Blagovest:你可能是对的。确认一种或另一种方式需要对各种编译器进行测试。没有做过那个测试,老实说,我没有特别的期望。 someintson_top_of_stack 很可能是相邻的,但它们也可以是相反的顺序(我可以想象这样做的正当理由)。无论如何,我相信我们都同意,做任何假设既不明智,也没有必要。
  • @Keith:你根本不能依赖变量排序(而且on_top_of_stack 可能除了寄存器之外什么都没有分配,尤其是在优化的构建中)。此外,请参阅此答案 - stackoverflow.com/questions/4575697/… - 了解 MSVC 仅因为变量的 name 更改而更改变量分配顺序的示例 - 即使在未优化的构建中也是如此。我有点惊讶。
【解决方案2】:

是的,如果程序无法访问该地址的内存,它可能会出现段错误。在您的情况下,由于数组在堆栈上分配并且只有 100 字节长并且堆栈大小明显更大(即 Linux 2.4.X 上的每个线程 8 MB),因此不太可能存在未初始化的数据。但在某些情况下,它可能会崩溃。无论哪种情况,这段代码都是错误的,像 Valgrind 这样的分析器应该能够帮助您解决它。

【讨论】:

  • 更接近。您也使用了类似 unix 的机器的示例,其中堆栈位于虚拟内存的顶部(问题的最高地址)并向下增长。这种一次性访问会碰到堆栈上的其他东西,并且在 unix 机器上总是会碰到一些东西。至少,参数计数位于堆栈的最顶部。
【解决方案3】:

第二行可以真正导致任何事情发生,并且就语言规范而言仍然是正确的。它可能会打印乱码,可能由于分段错误或其他原因而崩溃,可能会导致整个东海岸断电,或者可能导致规范的 demons to fly out of your nose...

这就是undefined behaviour 的魔力。

【讨论】:

  • +1:这是为数不多的正确答案之一。访问 someints[100] 是未定义的行为。 (旁白:形成指向someints[100] 的指针不是未定义的行为;它是明确允许的行为。想想std::vector::end()。)
猜你喜欢
  • 2015-05-11
  • 2013-06-05
  • 2020-10-29
  • 1970-01-01
  • 2017-03-02
  • 1970-01-01
  • 2017-06-17
  • 2016-08-08
  • 1970-01-01
相关资源
最近更新 更多