tl;dr
The solution is to increase the stack size. e.g., when using Visual Studio 2022, pass in /STACK:<reserve>[,commit]
; details here: https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-170&viewFallbackFrom=vs-2017.
Clarification: this does not mean that the global object is created on the stack; it's likely due to stack space needed for temporary objects created to initialize the object contents; see the details below for the case when a std::array (whose size is known at compile time) is used instead of a std::vector. The std::array is wholly allocated in the data segment, IIRC. The internal storage for the vector is heap allocated, but the vector instance itself is in the data segment; the additional stack space is needed in the case of the vector for the temporaries.
Example with Details
The issue is that even globals have to be initialized by some thread. In the case of MSVC, from what I can tell, it's done by the main thread. If we have a global vector of 564,168 64-bit prime numbers declared something like this:
std::vector<int64_t> knownInt24PrimesVector = {
2, 3, 5, 7, 11,
13, 17, 19, 23, 29,
31, 37, 41, 43, 47,
...
...
8388461, 8388473, 8388539, 8388547, 8388571,
8388581, 8388587, 8388593,
};
The program compiles fine, but when it is run, it will crash. It shows in the debugger as:
Unhandled exception at 0x00007FF620824107 in isprime.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000002F19603000).
The call stack looks like this:
isprime.exe!__chkstk() Line 109
> isprime.exe!`dynamic initializer for 'knownInt24PrimesVector''() Line 112842
[External Code]
The threads window in the debugger shows this:
Not Flagged > 16252 0 Main Thread Main Thread isprime.exe!__chkstk
Not Flagged 22980 0 Worker Thread ntdll.dll thread ntdll.dll!00007ffefdb30b14
Not Flagged 13112 0 Worker Thread ntdll.dll thread ntdll.dll!00007ffefdb30b14
Not Flagged 5580 0 Worker Thread ntdll.dll thread ntdll.dll!00007ffefdb30b14
As can be seen from the call stack and the threads window, the huge (~4.5MB) vector is getting initialized by Main Thread
.
The default stack size is 1MB for programs compiled with MSVC. dumpbin
shows this (the 100000 is in hexadecimal even though it doesn't have the 0x
prefix):
> dumpbin.exe /headers .\isprime.exe | findstr /ispn stack
46: 100000 size of stack reserve
47: 1000 size of stack commit
Since the data is ~4.5MB in size, increasing the stack size via /STACK:0x00480000
fixes the problem. dumpbin
of the rebuilt program shows the stack reserve as 0x480000, which is 4,718,592.
> dumpbin.exe /headers .\isprime.exe | findstr /ispn stack
46: 480000 size of stack reserve
47: 1000 size of stack commit
Note that with the Visual Studio 2022 using the v143 toolchain, using a std::array<int64_t, 564168>
did not require the stack size to be changed from the default value, which is expected since the array size is known at compile time.
Similarly, neither did constructing the vector passing in the array::cbegin()
and array::cend()
iterators require a stack size increase.
Also, more of an FYI: Using the v141 toolchain (which VS 2017 ships with), the compiler crashed (no additional info other than a message to contact tech support) trying to compile the file.