为什么不会发生分割故障?

发布于 2025-01-19 17:55:10 字数 351 浏览 2 评论 0原文

我希望在执行下面的代码后会发生SEG错误,但事实并非如此。有人可以告诉我为什么吗?

int main(){
    float *arr;
    cout << arr[0] << "\n" --> This prints out a ZERO. I am expecting a seg-fault.
        
    cout << arr[1000] << "\n" --> This gives me a seg-fault
        
    return 0;
}

我想知道这是否是由于减轻撞车事故的编译器的“智能”设计。但是我不确定。

I am expecting a seg-fault to occurr after the execution of the code below, but it doesn't. Could someone tell me why?

int main(){
    float *arr;
    cout << arr[0] << "\n" --> This prints out a ZERO. I am expecting a seg-fault.
        
    cout << arr[1000] << "\n" --> This gives me a seg-fault
        
    return 0;
}

I am wondering if this due to the "smart" design of the compiler that alleviates the crash. But I can't be sure.

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

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

发布评论

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

评论(2

裂开嘴轻声笑有多痛 2025-01-26 17:55:10

由于指针 arr 未初始化,因此它的值可能是内存地址先前使用时的值。

在您的情况下,以前使用该内存地址的代码可能使用该内存地址来存储指针,即存储指向有效对象的另一个内存地址。即使该对象的生命周期同时已过期,操作系统可能无法检测到这一点,因为内存页面可能不是返回到运行状态 系统。因此,就操作系统而言,该内存页仍然可以被程序读取(并且可能也可写入)。这可能解释了为什么取消引用 arr 的未初始化值不会产生分段错误。

表达式 arr[1000] 将尝试取消引用与 arr 的未初始化值相距 4000 字节的地址(假设 sizeof(float)==4< /代码>)。内存页的典型大小为 4096 字节。因此,假设 arr 的未初始化值是指向 4096 字节内存页开头附近的内存地址,那么向该地址添加 4000 不会充分改变内存地址以使得该地址指向不同的内存页。但是,如果arr的未初始化值是指向内存页中间某处的内存地址,那么向该地址添加4000将使其指向不同的内存页(假设内存页大小为 4096 字节)。这可能解释了为什么操作系统以不同的方式处理这两个地址,以便一个内存访问会导致分段错误,而另一个内存访问不会失败。

然而,这都是猜测(我经常使用“可能”这个词就可以清楚地表明这一点)。您的代码不会导致分段错误可能还有另一个原因。无论如何,当您的程序调用未定义的行为(它通过取消引用未初始化的指针来实现)时,您不能依赖任何特定的行为。在某些平台上,它可能会导致分段错误,而在其他平台上,程序可能会正常运行。即使更改编译器设置(例如优化级别)也可能足以改变程序的行为。


我想知道这是否是由于编译器的“智能”设计减轻了崩溃。

在这种情况下,“聪明”的做法是报告某种错误(即崩溃),而不是尝试缓解崩溃。这是因为崩溃使错误更容易被发现。

您的程序没有立即崩溃的原因是您的编译器和操作系统都没有检测到错误。

如果您希望更可靠地检测此类错误,那么您可能需要考虑使用某些编译器提供的功能来尝试检测此类错误。例如,gcc 和 clang 都支持 AddressSanitizer。在这两个编译器上,您所要做的就是使用 -fsanitize=address 命令行选项进行编译。但是,这将导致编译器添加额外的检查,从而显着降低性能(大约两倍)并增加内存使用量。因此,这只能用于调试目的。

Since the pointer arr is not initialized, it probably has the value of whatever value that memory address had when it was previously used.

In your case, the code that used that memory address previously probably used that memory address for storing a pointer, i.e. for storing another memory address that points to a valid object. Even if the lifetime of that object has expired in the mean time, the operating system will probably not be able to detect this, because the memory page was probably not returned to the operating system. Therefore, as far as the operating system is concerned, that memory page is still readable (and possibly also writable) by the program. This probably explains why dereferencing the uninitialized value of arr does not produce a segmentation fault.

The expression arr[1000] will attempt to dereference an address that is 4000 bytes apart from the uninitialized value of arr (assuming sizeof(float)==4). A typical size of a memory page is 4096 bytes. Therefore, assuming that the uninitialized value of arr is a memory address that points near the start of a memory page of 4096 bytes, then adding 4000 to that address will not change the memory address sufficiently to make the address point to a different memory page. However, if the uninitialized value of arr is a memory address that points somewhere in the middle of a memory page, then adding 4000 to that address will make it point to a different memory page (assuming a memory page size of 4096 bytes). This probably explains why your operating system treats both addresses differently, so that one memory access causes a segmentation fault and the other memory access does not fail.

However, this is all speculation (which is made clear by my frequent use of the word "probably"). There could be another reason why your code does not cause a segmentation fault. In any case, when your program invokes undefined behavior (which it does by dereferencing an uninitialized pointer), you cannot rely on any specific behavior. On some platforms, it may cause a segmentation fault, while on other platforms, the program may work perfectly. Even changing the compiler settings (such as the optimization level) may be enough to change the behavior of the program.


I am wondering if this due to the "smart" design of the compiler that alleviates the crash.

The "smart" thing to do in such a case would be to report some kind of error (i.e. to crash), and not to attempt to alleviate the crash. This is because crashing makes the bug easier to find.

The reason why your program is not crashing immediately is that neither your compiler nor your operating system are detecting the error.

If you want such errors to be detected more reliably, then you may want to consider using a feature offered by some compilers that tries to detect such bugs. For example, both gcc and clang support AddressSanitizer. On those two compilers, all you have to do is compile with the -fsanitize=address command-line option. However, this will cause the compiler to add additional checks, which will significantly decrease performance (by a factor of about two) and increase memory usage. Therefore, this should only be done for debugging purposes.

哭泣的笑容 2025-01-26 17:55:10

我是期望出现SEG FAURT 出现...

您的程序具有未定义的行为,因为指针arr是不统治的,并且您正在提取它隐式。

未定义的行为意味着任何事物 1 可能发生,包括但不限于 提供了预期的输出。但是永远不要依靠(或基于结论),该程序的输出不确定行为。

因此,您看到的(也许看到)的输出是不确定行为的结果。正如我所说,不依赖具有UB程序的程序的输出。该程序可能只是崩溃。

例如,在这里该程序不会崩溃,但是在这里它崩溃了。

因此,使程序正确的第一步是删除UB。 然后,只有这样,您才能开始对程序的输出进行推理。


1 有关未定义行为的更精确的定义,请参见 提到的地方:对程序的行为没有任何限制

I am expecting a seg-fault to occurr...

Your program has undefined behavior since the pointer arr is uninitialized and you're dereferencing it implicitly.

Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.

So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash.

For example, here the program doesn't crash but here it crashes.

So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.


1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.

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