一旦为索引 1 赋值,就会出现预期的分段错误吗?

发布于 2024-09-06 03:28:38 字数 546 浏览 3 评论 0原文

在代码片段中,我预计在尝试为 count[1] 分配值时会出现分段错误。然而,代码继续并执行第二个 for 循环,仅在程序终止时指示分段错误。

#include <stdio.h>

int main()
{
        int count[1];
        int i;

        for(i = 0; i < 100; i++)
        {
                count[i] = i;
        }
        for(i = 0; i < 100; i++)
        {
                printf("%d\n", count[i]);
        }
        return 0;
}

有人可以解释发生了什么吗?

修改原因: 根据用户的意见改进了示例代码, int count[0] -> > int count[0] -> int 计数[1], 也避免激烈的战争。

In the code snippet, I expected a segmentation fault as soon as trying to assign a value to count[1]. However the code continues and executes the second for-loop, only indicating a segmentation fault when the program terminates.

#include <stdio.h>

int main()
{
        int count[1];
        int i;

        for(i = 0; i < 100; i++)
        {
                count[i] = i;
        }
        for(i = 0; i < 100; i++)
        {
                printf("%d\n", count[i]);
        }
        return 0;
}

Could someone explain what is happening?

Reasons for edit:
Improved the example code as per comments of users,
int count[0] -> int count[1],
too avoid flame wars.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

感情洁癖 2024-09-13 03:28:38

你写的内容超出了数组的范围。这并不意味着您会遇到分段错误。这只是意味着您有未定义的行为。您的程序的行为不再受 C 标准的限制。任何事情都可能发生(包括看起来有效的程序)——段错误只是一种可能的结果。

实际上,当您尝试访问操作系统未映射到进程的内存页时,就会发生分段错误。在典型的 x86 PC 上,每个页面都是 4KB,因此基本上,您的进程可以访问 4KB 块中的内存,并且如果您在当前块之外写入,则只会出现段错误。

使用您使用的小索引,您仍然停留在分配给您的进程的当前内存页面内,因此 CPU 不会检测到您正在越界访问内存。

You're writing beyond the bounds of the array. That doesn't mean you're going to get a segmentation fault. It just means that you have undefined behavior. Your program's behavior is no longer constrained by the C standard. Anything could happen (including the program seeming to work) -- a segfault is just one possible outcome.

In practice, a segmentation fault occurs when you try to access a memory page that is not mapped to your process by the OS. Each page is 4KB on a typical x86 PC, so basically, your process is given access to memory in 4KB chunks, and you only get a segfault if you write outside the current chunk.

With the small indices you're using, you're still staying within the current memory page, which is allocated to your process, and so the CPU doesn't detect that you're accessing memory out of bounds.

硪扪都還晓 2024-09-13 03:28:38

当您写入超出数组范围时,您可能仍在进程控制下将数据写入内存区域;您几乎肯定还会覆盖其他软件使用的内存,例如堆或堆栈帧管理代码。只有当该代码执行时,例如当当前函数尝试返回时,您的代码才可能出错。事实上,你真的希望出现段错误。

When you write beyond the array bounds, you are probably still writing data into the area of memory under the control of your process; you are also almost certainly overwriting memory used by other software, such as heap or stack frame management code. It is only when that code executes, such as when the current function attempts to return, that your code might go awry. Actually, you really hope for a seg fault.

耶耶耶 2024-09-13 03:28:38

您的代码已损坏:

seg.c:5: warning: ISO C forbids zero-size array ‘count’

始终以高警告级别进行编译,例如 GCC 的 -Wall -pedantic

编辑:

您实际上所做的是破坏main的函数堆栈帧。由于现在堆栈几乎总是向下增长,所以发生了这样的情况:

  • 第一个循环覆盖保存 main 参数的堆栈内存并将地址返回到 crt0 例程。
  • 第二个循环愉快地读取该内存。
  • main 返回时,由于返回地址已被 fubar-ed,因此会触发分段错误。

这是缓冲区溢出的典型案例,也是许多网络蠕虫的基础。

在调试器下运行程序并检查局部变量的地址。在 GDB 中,您可以说set backtrace past-main,这样 backtrace 就会向您显示通向 main 的所有例程。

顺便说一句,无需零长度数组也可以实现相同的效果 - 只需使其大小小于循环迭代的次数即可。

Your code is broken:

seg.c:5: warning: ISO C forbids zero-size array ‘count’

Always compile with high warning levels, for example -Wall -pedantic for GCC.

Edit:

What you are effectively doing is corrupting mains function stack frame. Since stack nowadays pretty much always grows down, this is what's happening:

  • First loop overrides stack memory holding main parameters and return address to crt0 routines.
  • Second loop happily reads that memory.
  • When main returns the segmentation fault is triggered since return address is fubar-ed.

This is a classic case of buffer overrun and is the basis of many network worms.

Run the program under the debugger and check the addresses of local variables. In GDB you can say set backtrace past-main so backtrace would show you all the routines leading to main.

By the way, the same effect could be achieved without zero-length array - just make its size smaller then number of loop iterations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文