I have the code listed below and it reports a stack overflow when I run it.
I use pass by value to showTest()
.
What I expect is that it will make a copy of the Test
struct to the stack (pushed to the stack), then at the end of the function call the Test
struct will be released (popped off of the stack).
So I make a call for three times. It is supposed to push onto the stack and pop off at the end of each function call.
I don't see any stack issue if it pushes on and pops off of the stack each time the function is called.
However, when I run this code, it reports a stack overflow exception on the first line of main
. (I use Visual Studio 2017.)
If I remove one of the showTest()
function calls then I can get it work.
Any feedback would be highly appreciated.
#include <iostream>
struct Test
{
static int Userid;
int data[100000] = { };
Test()
{
++Userid;
};
};
int Test::Userid = 0;
void showTest(Test i_myint)
{
std::cout << "test" << std::endl;
}
int main()
{
Test *pint = new Test();
showTest(*pint);
Test *pint2 = new Test();
showTest(*pint2);
Test *pint3 = new Test();
showTest(*pint3);
return 0;
}
What evidently happens here is deferred stack popping.
In C and C++ the common calling convention is that the caller pops arguments from the stack. As a common optimisation, many compilers don't pop arguments after each call, but do that after a number of calls and pop all the accumulated arguments together. This saves a few instructions, at the expense of a larger stack which may overflow.
In MSVC, when optimisations are disabled, the compiler allocates and checks the stack beforehand for all the calls it will need in a given function. This is why the program crashes even before it prints anything.
See corresponding assembly
Some of the first instructions in main
are
mov eax, 1200120 ; 00124ff8H
call __chkstk
sub rsp, rax
This number is exactly what is needed to fit three instances of the object on the stack.
When optimisations are enabled, the compiler is smart enough to reuse the stack, so there's no crash.
Optimised assembly
mov eax, 400032 ; 00061aa0H
call __chkstk
sub rsp, rax
Enough for a single instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With