11
struct MemBlock {

    char mem[1024];

    MemBlock operator*(const MemBlock &b) const {

        return MemBlock();
    }

} global;

void foo(int step = 0) {

    if (step == 10000)
    {
        global = global * MemBlock();
    }
    else foo(step + 1);
}

int main() {

    foo();
    return 0;
}

Program received signal SIGSEGV, Segmentation fault. 0x08048510 in foo (step=4000) at t.cpp:12 12 void foo(int step = 0) {

It seems that the MemBlock() instance costs a lot of stack memory though it hasn't been called yet (check gdb info).

And when I use global = global * global instead, the program exits normally.

Can anybody explain the inner mechanism?

4
  • 1
    You receive the segfault because you are recursively calling foo 10000 times, it has nothing to do with the MemBlock class Commented Jul 20, 2012 at 12:23
  • @TomKnapen, no, you're wrong. a) it dies on 4001's call for me. b)if you remove the stuff inside if, it doesnt die at all. Commented Jul 20, 2012 at 12:25
  • 3
    @SingerOfTheFall my comment may have been better when it readed 'trying to call foo 10000 times', but the point stays: it is the recursion's fault. And if you remove the if block, the compiler will probably optimize the function call away, thus removing the recursion. Commented Jul 20, 2012 at 12:27
  • You might want to add int* test = &step variable and observe the different values on the call stack. I'll bet this shows the actual stack memory allocated in the debugger. Commented Jul 20, 2012 at 14:19

1 Answer 1

15

The compiler is reserving the stack space for the MemBlock instance on each call to foo, regardless of the control flow within foo. This is a common optimisation to prevent having to repeatedly adjust the stack pointer within the function. Instead, the compiler calculates the maximum stack space required and on entry to the function adjusts the stack pointer by that amount.

As you've observed, this results in losing stack space reserved for objects you don't actually use. The answer is to not do that; if you're only using some large-footprint objects within certain branches then separate those branches out into their own function.

Incidentally, this is why archaic versions of C required all function-scope variables to be declared at the top of the function; so that the compiler can easily work out how much stack space the function requires.

Sign up to request clarification or add additional context in comments.

8 Comments

I like the history lesson at the end, I didn't know that tidbit :)
I tried to replace the expression with MemBlock *t = new MemBlock; global = global * *t; I thought it would be constructed at runtime an d it would not effect the stack space. But still fault. What's the problem?
+1 for "if you're only using some large-footprint objects within certain branches then separate those branches out into their own function.".. and "Incidentally, this is why archaic versions of C required all function-scope variables to be declared at the top of the function; so that the compiler can easily work out how much stack space the function requires"
@ymfoi in that case the compiler is reserving stack space for the return value of the expression global * *t!
@ecatmur Sorry, I don't quite catch it. What's the "return value"?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.