c++visual-c++memory-managementstack-overflow

Why would a C++ program allocate more memory for local variables than it would need in the worst case?


Inspired by this question.

Apparently in the following code:

#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    if( GetTickCount() > 1 ) {
        char buffer[500 * 1024];
        SecureZeroMemory( buffer, sizeof( buffer ) );
    } else {
        char buffer[700 * 1024];
        SecureZeroMemory( buffer, sizeof( buffer ) );
    }
    return 0;
}

compiled with default stack size (1 megabyte) with Visual C++ 10 with optimizations on (/O2) a stack overflow occurs because the program tries to allocate 1200 kilobytes on stack.

The code above is of course slightly exaggerated to show the problem - uses lots of stack in a rather dumb way. Yet in real scenarios stack size can be smaller (like 256 kilobytes) and there could be more branches with smaller objects that would induce a total allocation size enough to overflow the stack.

That makes no sense. The worst case would be 700 kilobytes - it would be the codepath that constructs the set of local variables with the largest total size along the way. Detecting that path during compilation should not be a problem.

So the compiler produces a program that tries to allocate even more memory than the worst case. According to this answer LLVM does the same.

That could be a deficiency in the compiler or there could be some real reason for doing it this way. I mean maybe I just don't understand something in compilers design that would explain why doing allocation this way is necessary.

Why would the compiler want a program allocate more memory than the code needs in the worst case?


Solution

  • The following code when compiled using GCC 4.5.1 on ideone places the two arrays at the same address:

    #include <iostream>
    
    int main()
    {
      int x;
      std::cin >> x;
    
      if (x % 2 == 0)
      {
        char buffer[500 * 1024]; 
        std::cout << static_cast<void*>(buffer) << std::endl;
      }
    
      if (x % 3 == 0)
      {
        char buffer[700 * 1024]; 
        std::cout << static_cast<void*>(buffer) << std::endl;
      }
    }
    

    input: 6

    output:
    0xbf8e9b1c
    0xbf8e9b1c

    The answer is probably "use another compiler" if you want this optimization.