In Microsoft Visual C++ 2010 I created a program which delibrately causes a stack overflow. When I run the program using "start debugging" an error is thrown when stack overflow occurs. When I run it with "start without debugging" no error is thrown and the program just terminates silently as if it had successfully completed. Could someone explain to me what's going on? Also do any other compilers not throw errors on stack overflow?
在Microsoft Visual C ++ 2010中,我创建了一个程序,该程序可能会导致堆栈溢出。当我使用“开始调试”运行程序时,发生堆栈溢出时会引发错误。当我使用“start without debugging”运行它时,不会抛出任何错误,程序只是静默终止,就像它已成功完成一样。有人可以向我解释发生了什么事吗?还有其他任何编译器不会在堆栈溢出时抛出错误吗?
(I thought this would be the right place to ask a question about stack overflow.)
(我认为这是提出有关堆栈溢出的问题的正确位置。)
6 个解决方案
#1
9
C++ won't hold your hand as a managed enviroment does. Having a stack overflow means undefined behaviour.
C ++不会像托管环境那样牵着你的手。堆栈溢出意味着未定义的行为。
#2
5
A stack overflow is undefined behaviour. The compiler is well within it's rights to ignore it or cause any event to happen.
堆栈溢出是未定义的行为。编译器完全有权忽略它或导致任何事件发生。
#3
4
Because when your process stack overflows, it is no longer a valid process. Displaying an error message requires a stack.
因为当进程堆栈溢出时,它不再是一个有效的进程。显示错误消息需要堆栈。
Raymond Chen went over this recently.
Raymond Chen最近接手了这个。
As for why the debugger is able to throw such an exception, in that case the process is being kept around because it's attached in debugging mode to the debugger's process. Your process isn't displaying the error, the debugger is.
至于为什么调试器能够抛出这样的异常,在这种情况下,进程被保留,因为它以调试模式附加到调试器的进程。您的进程没有显示错误,调试器是。
On Windows machines, you can catch the SEH exception which corresponds to a stack overflow. For an example, you can see boost::regex's source code (Google for BOOST_REGEX_HAS_MS_STACK_GUARD).
在Windows机器上,您可以捕获与堆栈溢出相对应的SEH异常。例如,您可以看到boost :: regex的源代码(Google for BOOST_REGEX_HAS_MS_STACK_GUARD)。
#4
2
It might well be that the compiler optimized the intended stack overflow away. Consider the following pseudo-code example:
很可能是编译器优化了预期的堆栈溢出。请考虑以下伪代码示例:
void RecursiveMethod(int n)
{
if (n % 1024 == 0)
print n;
// call recursively
RecursiveMethod(n + 1);
}
The method will call itself recursively and overflow the stack pretty quickly because there is no exit condition.
该方法将递归调用自身并快速溢出堆栈,因为没有退出条件。
However, most compilers use tail recursion, a technique which will transfer the recursive function call into a loop construct.
但是,大多数编译器都使用尾递归,这种技术将递归函数调用转换为循环结构。
It should be noted that with tail recursion, the above program would run in an endless loop and not exit silently.
应该注意的是,对于尾递归,上面的程序将在无限循环中运行而不是静默退出。
Bart de Smet has a nice blog article where explains how this technique works in .NET:
Bart de Smet有一篇很好的博客文章,解释了这种技术在.NET中是如何工作的:
The Case of The Failed Demo – *Exception on x64
失败的演示案例 - x64上的*Exception
#5
1
In a debug build, a number of stack checks are put in place to help you detect problems such as stack overflows, stack corruption etc. They are not present in release builds because they would affect the performance of the application. As others have pointed out, a stack overflow is undefined behaviour, so the compiler is not required to implement such stack checks at all.
在调试版本中,会进行大量的堆栈检查以帮助您检测堆栈溢出,堆栈损坏等问题。它们不会出现在发布版本中,因为它们会影响应用程序的性能。正如其他人所指出的,堆栈溢出是未定义的行为,因此编译器根本不需要实现这样的堆栈检查。
When you're in a debugging environment, the runtime checks will help you detect problems that will also occur in your release build, therefore, if you fix all the problems detected in your debug build, then they should also be fixed in your release build . . . in theory. In practice, sometimes bugs that you see in your debug build are not present in your release build or vice versa.
当您处于调试环境中时,运行时检查将帮助您检测发布版本中也会出现的问题,因此,如果您修复了调试版本中检测到的所有问题,那么它们也应该在发布版本中修复。 。 。理论上。实际上,有时您在调试版本中看到的错误在您的发布版本中不存在,反之亦然。
Stack overflows shouldn't happen. Generally, stack overflows occur only by unintentional recursive function calling, or by allocating a large enough buffer on the stack. The former is obviously a bug, and the latter should use the heap instead.
堆栈溢出不应该发生。通常,堆栈溢出仅通过无意的递归函数调用或通过在堆栈上分配足够大的缓冲区来发生。前者显然是一个bug,而后者应该使用堆。
#6
1
In debugging mode, you want the overhead. You want it to detect if you broke your stack, overflowed your buffers, etc. This overhead is built into the debug instrumentation, and the debugger. In high level terms the debug instrumentation is extra code and data, put there to help flag errors, and the debugger is there to detect the flagged errors and notify the user (in addition to helping you debug, of course).
在调试模式下,您需要开销。您希望它检测您是否损坏了堆栈,溢出了缓冲区等。此开销内置于调试工具和调试器中。在高级术语中,调试工具是额外的代码和数据,放在那里以帮助标记错误,调试器可以检测标记的错误并通知用户(当然除了帮助您调试)。
If you are running with the project compiled in release mode, or without a debugger attached, there is no one to hear the screaming of your program when it dies :) If a tree falls in the forest...
如果您正在运行在发布模式下编译的项目,或者没有附加调试器,那么当程序死亡时,没有人可以听到程序的尖叫:)如果一棵树落在森林里......
Depending on how you program, C++ is programming without training wheels. If you hit a wall, no one is going to be there to tell you that you screwed up. You will just crash and burn, or even worse, crash and keep running along in a very crippled state, without knowing anything is wrong. Because of this, it can be very fast. There are no extra checks or safe guards to keep it from blazing through your program with the full speed and potential of the processor (and, of course, how many extra steps you coded into your program).
根据您的编程方式,C ++在没有训练轮的情况下进行编程。如果你撞墙,没有人会在那里告诉你,你搞砸了。你将崩溃和燃烧,甚至更糟糕的是,崩溃并继续在一个非常瘫痪的状态下运行,而不知道什么是错的。因此,它可以非常快。没有额外的检查或安全防护措施,以防止它在处理器的全速和潜力(以及当然,您编入程序的多少额外步骤)的程序中肆无忌惮。
#1
9
C++ won't hold your hand as a managed enviroment does. Having a stack overflow means undefined behaviour.
C ++不会像托管环境那样牵着你的手。堆栈溢出意味着未定义的行为。
#2
5
A stack overflow is undefined behaviour. The compiler is well within it's rights to ignore it or cause any event to happen.
堆栈溢出是未定义的行为。编译器完全有权忽略它或导致任何事件发生。
#3
4
Because when your process stack overflows, it is no longer a valid process. Displaying an error message requires a stack.
因为当进程堆栈溢出时,它不再是一个有效的进程。显示错误消息需要堆栈。
Raymond Chen went over this recently.
Raymond Chen最近接手了这个。
As for why the debugger is able to throw such an exception, in that case the process is being kept around because it's attached in debugging mode to the debugger's process. Your process isn't displaying the error, the debugger is.
至于为什么调试器能够抛出这样的异常,在这种情况下,进程被保留,因为它以调试模式附加到调试器的进程。您的进程没有显示错误,调试器是。
On Windows machines, you can catch the SEH exception which corresponds to a stack overflow. For an example, you can see boost::regex's source code (Google for BOOST_REGEX_HAS_MS_STACK_GUARD).
在Windows机器上,您可以捕获与堆栈溢出相对应的SEH异常。例如,您可以看到boost :: regex的源代码(Google for BOOST_REGEX_HAS_MS_STACK_GUARD)。
#4
2
It might well be that the compiler optimized the intended stack overflow away. Consider the following pseudo-code example:
很可能是编译器优化了预期的堆栈溢出。请考虑以下伪代码示例:
void RecursiveMethod(int n)
{
if (n % 1024 == 0)
print n;
// call recursively
RecursiveMethod(n + 1);
}
The method will call itself recursively and overflow the stack pretty quickly because there is no exit condition.
该方法将递归调用自身并快速溢出堆栈,因为没有退出条件。
However, most compilers use tail recursion, a technique which will transfer the recursive function call into a loop construct.
但是,大多数编译器都使用尾递归,这种技术将递归函数调用转换为循环结构。
It should be noted that with tail recursion, the above program would run in an endless loop and not exit silently.
应该注意的是,对于尾递归,上面的程序将在无限循环中运行而不是静默退出。
Bart de Smet has a nice blog article where explains how this technique works in .NET:
Bart de Smet有一篇很好的博客文章,解释了这种技术在.NET中是如何工作的:
The Case of The Failed Demo – *Exception on x64
失败的演示案例 - x64上的*Exception
#5
1
In a debug build, a number of stack checks are put in place to help you detect problems such as stack overflows, stack corruption etc. They are not present in release builds because they would affect the performance of the application. As others have pointed out, a stack overflow is undefined behaviour, so the compiler is not required to implement such stack checks at all.
在调试版本中,会进行大量的堆栈检查以帮助您检测堆栈溢出,堆栈损坏等问题。它们不会出现在发布版本中,因为它们会影响应用程序的性能。正如其他人所指出的,堆栈溢出是未定义的行为,因此编译器根本不需要实现这样的堆栈检查。
When you're in a debugging environment, the runtime checks will help you detect problems that will also occur in your release build, therefore, if you fix all the problems detected in your debug build, then they should also be fixed in your release build . . . in theory. In practice, sometimes bugs that you see in your debug build are not present in your release build or vice versa.
当您处于调试环境中时,运行时检查将帮助您检测发布版本中也会出现的问题,因此,如果您修复了调试版本中检测到的所有问题,那么它们也应该在发布版本中修复。 。 。理论上。实际上,有时您在调试版本中看到的错误在您的发布版本中不存在,反之亦然。
Stack overflows shouldn't happen. Generally, stack overflows occur only by unintentional recursive function calling, or by allocating a large enough buffer on the stack. The former is obviously a bug, and the latter should use the heap instead.
堆栈溢出不应该发生。通常,堆栈溢出仅通过无意的递归函数调用或通过在堆栈上分配足够大的缓冲区来发生。前者显然是一个bug,而后者应该使用堆。
#6
1
In debugging mode, you want the overhead. You want it to detect if you broke your stack, overflowed your buffers, etc. This overhead is built into the debug instrumentation, and the debugger. In high level terms the debug instrumentation is extra code and data, put there to help flag errors, and the debugger is there to detect the flagged errors and notify the user (in addition to helping you debug, of course).
在调试模式下,您需要开销。您希望它检测您是否损坏了堆栈,溢出了缓冲区等。此开销内置于调试工具和调试器中。在高级术语中,调试工具是额外的代码和数据,放在那里以帮助标记错误,调试器可以检测标记的错误并通知用户(当然除了帮助您调试)。
If you are running with the project compiled in release mode, or without a debugger attached, there is no one to hear the screaming of your program when it dies :) If a tree falls in the forest...
如果您正在运行在发布模式下编译的项目,或者没有附加调试器,那么当程序死亡时,没有人可以听到程序的尖叫:)如果一棵树落在森林里......
Depending on how you program, C++ is programming without training wheels. If you hit a wall, no one is going to be there to tell you that you screwed up. You will just crash and burn, or even worse, crash and keep running along in a very crippled state, without knowing anything is wrong. Because of this, it can be very fast. There are no extra checks or safe guards to keep it from blazing through your program with the full speed and potential of the processor (and, of course, how many extra steps you coded into your program).
根据您的编程方式,C ++在没有训练轮的情况下进行编程。如果你撞墙,没有人会在那里告诉你,你搞砸了。你将崩溃和燃烧,甚至更糟糕的是,崩溃并继续在一个非常瘫痪的状态下运行,而不知道什么是错的。因此,它可以非常快。没有额外的检查或安全防护措施,以防止它在处理器的全速和潜力(以及当然,您编入程序的多少额外步骤)的程序中肆无忌惮。