当我写完数组末尾时,为什么程序不会崩溃?
|
为什么下面的代码在没有运行时崩溃的情况下运行?
而且大小完全取决于机器/平台/编译器!我什至在一台64位计算机上最多可以放弃200个。如何在OS中检测到主要功能的分段错误?
int main(int argc, char* argv[])
{
int arr[3];
arr[4] = 99;
}
此缓冲区空间从何而来?这是分配给进程的堆栈吗?
没有找到相关结果
已邀请:
9 个回复
苦诫
编译并执行后,将生成一个核心转储:
现在使用gdb进行事后分析:
呵呵,当有人在分配的200个项目之外写程序时,该程序没有出现段错误,而是在i = 1008时崩溃了,为什么? 输入页面。 一种可以在UNIX / Linux上以多种方式确定页面大小,一种方式是使用系统函数sysconf(),如下所示:
它给出了输出: 该系统的页面大小为4096字节。 或者可以像这样使用命令行实用程序getconf:
验尸 事实证明,段错误不是在i = 200发生的,而是在i = 1008发生的,让我们找出原因。启动gdb进行事后分析:
q在地址0x804a35c处结束,或者说q [199]的最后一个字节在那个位置。页大小是我们之前看到的4096字节,并且该机器的32位字大小使虚拟地址分解为20位页号和12位偏移量。 q []以虚拟页码结尾: 0x804a = 32842 抵消: 0x35c = 860 所以仍然有: 4096-864 = 3232 分配了q []的内存页面上剩余的字节数。该空间可以容纳: 3232/4 = 808 整数,并且代码将其视为在位置200至1008处包含q的元素。 我们都知道这些元素不存在,编译器也没有抱怨,但硬件也没有,因为我们对该页面具有写权限。仅当i = 1008时q []引用了我们没有写权限的其他页面上的地址时,虚拟内存hw才检测到此错误并触发了段错误。 整数存储在4个字节中,表示此页面包含808(3236/4)个其他伪元素,表示从q [200],q [201]一直访问到元素199仍然完全合法。 + 808 = 1007(q [1007])而不触发段故障。访问q [1008]时,您将进入一个权限不同的新页面。
很缴
先对冈蒲
,这是因为访问的内存超出了栈顶,没有映射任何内容。 如果此时的总数小于堆栈已使用部分的大小,那么它将正常工作并稍后崩溃-实际上,在将返回地址存储在堆栈上的平台上(对于x86 /从您的函数返回时)。那是因为CPU指令“ 8”实际上是从堆栈(返回地址)中取出一个字并在那里重定向执行。如果该地址包含任何垃圾,而不是预期的代码位置,则会发生异常,并且程序将死亡。 为了说明这一点:调用ѭ9时,堆栈如下所示(在32位x86 UNIX程序上):
当“ 9”开始时,它将为各种目的在堆栈上分配空间,以托管您要溢出的数组。这将使其看起来像:
这意味着您可以愉快地访问
以外的地方。 对于由于缓冲区溢出而导致的各种崩溃的品尝者,请尝试以下一种方法:
并查看当缓冲区溢出一点点(例如10)与崩溃超出堆栈末尾时相比,崩溃将有何不同。尝试使用不同的优化级别和不同的编译器。很好地说明了这一点,因为它既显示了异常行为(不一定总是正确地打印所有
),又在各个地方崩溃,甚至可能是无尽的循环(例如,如果编译器将
或
放入堆栈中,并且代码覆盖了它在循环中)。
脖呐
您会抛出异常。 因此,C ++提供了检查和未检查的接口。由您自己选择要使用的那个。
购藏盗码韦
目浆搽
公藕
,而C标准和C ++标准都需要
。 关于唯一对ѭ19满意的编译器是Microsoft的Visual C ++。 这是一个编译器缺陷,但是由于Microsoft有很多示例文档,甚至生成19英镑的代码生成工具,他们可能永远也无法修复它。但是,请考虑键入Microsoft特定的“ 19”比标准的“ 20”多键入一个字符。那么为什么不遵循标准呢? 干杯,……
粱委教
桑娠贯涤