简体   繁体   English

为什么 cout 的访问冲突和 printf 的堆栈溢出

[英]Why Access Violation for cout and Stack Overflow for printf

I wanted to know why Access Violation occurs for cout and Stack Overflow for printf in the following two code snippets.我想知道为什么在以下两个代码片段中 cout 会发生访问冲突和 printf 会发生堆栈溢出。

I wanted to know why Access Violation for the first code instead of the Stack Overflow.我想知道为什么第一个代码的访问冲突而不是堆栈溢出。

First code which I get Access Violation :我得到访问冲突的第一个代码:

void Test();

void Test()
{
    static int i = 0;
        cout << i++ << endl;    
    Test();
}
int main() 
{

    Test();
    
    return 0;
}

Second code which I get Stack Overflow :我得到堆栈溢出的第二个代码:

void Test();

void Test()
{
    static int i = 0;
        printf("%d\n", i++);    
    Test();
}
int main() 
{

    Test();
    
    return 0;
}

I assume you understand that both functions crash due to exhaustion of the stack after an attempt at infinite recursion.我假设您了解在尝试无限递归后,由于堆栈耗尽,这两个函数都会崩溃。 I think what you are asking is: why would the cout example not crash with "Stack Overflow" also?我认为您要问的是:为什么 cout 示例也不会因“堆栈溢出”而崩溃?

I do not think the answer has to do with the compiler's detection of tail recursion.我认为答案与编译器对尾递归的检测无关。 If the compiler optimized the recursion away, neither example should crash.如果编译器优化了递归,则两个示例都不会崩溃。

I have a guess as to what is going on.我对正在发生的事情有一个猜测。 "Stack Overflow" exception is implemented in some cases (eg, Windows) with a single Virtual Memory "guard page" allocated at the end of the stack. “堆栈溢出”异常在某些情况下(例如,Windows)通过在堆栈末尾分配的单个虚拟内存“保护页面”实现。 When a stack access hits this guard page a special exception type is generated.当堆栈访问命中此防护页时,会生成一种特殊的异常类型。

Since the Intel small-granularity page is 4096 bytes long, the guard page stands guard over a range of memory that size.由于 Intel 小粒度页面的长度为 4096 字节,因此保护页面会保护该大小的内存范围。 If a function call allocates more than 4096 bytes of local variables, it is possible that the first stack access from it will actually stretch beyond the guard page.如果一个函数调用分配了超过 4096 字节的局部变量,那么它的第一个堆栈访问实际上可能会超出保护页。 The next page can be expected to be unreserved memory, so an access violation would make sense in that case.下一页可能是未保留的内存,因此在这种情况下访问冲突是有意义的。

Of course you don't explicitly declare any local variables in your example.当然,您没有在示例中显式声明任何局部变量。 I would assume that one of the operator<<() methods allocates more than a page of local variables.我假设其中一个 operator<<() 方法分配的局部变量不止一页。 In other words, that the Access Violation occurs near the beginning of an operator<<() method or some other part of the cout implementation (temporary object constructors, etc.)换句话说,访问冲突发生在 operator<<() 方法的开头附近或 cout 实现的其他部分(临时对象构造函数等)

Also, even in the function you wrote, the operator<<() implementations are going to need to create some storage for intermediate results.此外,即使在您编写的函数中, operator<<() 实现也需要为中间结果创建一些存储空间。 That storage is probably allocated as local storage by the compiler.该存储可能被编译器分配为本地存储。 I doubt it would add up to 4k in your example, though.不过,我怀疑在您的示例中它会增加到 4k。

The only way to really understand would be to see a stack trace of the access violation to see what instruction is triggering it.真正理解的唯一方法是查看访问冲突的堆栈跟踪,以查看触发它的指令。

Got a stack trace of the access violation and a disassembly around the area of the faulting opcode?是否有访问冲突的堆栈跟踪和错误操作码区域周围的反汇编?

If you are using the Microsoft C compiler, another possibility is that printf() and your own function were compiled with /Ge and operator<<() was not, or that only your function was compiled with /Ge and factors similar to those described above coincidentally cause the behavior you see -- because in the printf() example the crash happens while your function is being called and in the operator<<() case while you are calling the library.如果您使用的是 Microsoft C 编译器,另一种可能是 printf() 和您自己的函数是用 /Ge 编译的,而 operator<<() 不是,或者只有您的函数是用 /Ge 编译的,并且因素与所描述的类似以上巧合导致您看到的行为 - 因为在 printf() 示例中,崩溃发生在您的函数被调用时以及在 operator<<() 情况下,当您调用库时。

Both recursive functions will never stop.这两个递归函数永远不会停止。 It seems that in the second case, no tail optimization is done by the compiler, thus the stack overflow.似乎在第二种情况下,编译器没有做尾部优化,因此堆栈溢出。

Both functions trigger a stack overflow on my machine.这两个函数都会在我的机器上触发堆栈溢出。 I am compiling it with MS Visual Studio 2005. Maybe you should specify your platform & compiler, that will help to investigate...我正在用 MS Visual Studio 2005 编译它。也许你应该指定你的平台和编译器,这将有助于调查......

Maybe you compile something in the debug mode and your "cout" implementation includes some checkups, that cannot be performed due to the stack corruption?也许你在调试模式下编译了一些东西,你的“cout”实现包括一些检查,由于堆栈损坏而无法执行? Maybe your compiler generated the code, that tries to recover from stack overflow and pops an invalid return address?也许您的编译器生成了试图从堆栈溢出中恢复并弹出无效返回地址的代码? Maybe you are running it on the mobile device?也许您正在移动设备上运行它? Hard to say without knowing the platform and the compiler.不知道平台和编译器就很难说。

Infinite recursive call is for the stack overflow.无限递归调用是针对堆栈溢出的。 As for the access violation... it really depends on the implementation of STL streams.至于访问冲突……这真的取决于STL流的实现。 You need to take a look on the source code of streams to find out...您需要查看流的源代码以找出...

Though most people misunderstood your question, the answer is in there.尽管大多数人误解了您的问题,但答案就在那里。

The second example ends with stack overflow because every function call is pushing a frame onto the stack.第二个示例以堆栈溢出结束,因为每个函数调用都将一个帧压入堆栈。 Eventually, it gets too big.最终,它变得太大了。 I agree with Cătălin Pitiș, that it'd be hard to know why the streams example is ending with an access violation without looking at the source.我同意 Cătălin Pitiș 的观点,即很难知道为什么流示例以访问冲突结束而不查看源。

这让我想起了堆栈被破坏和调试器没有捕捉到失败的程序崩溃的问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM