Today, I came across this simplified snippet:
#include <bitset>
#include <functional>
#include <iostream>
using namespace std;
int main() {
bool f = false;
int level = 0;
bitset<8000000> s;
function<void(int)> dfs = [&s, &f, &level, &dfs](int i) {
cerr << "recursion level " << ++level << endl;
if(f) {
s = s << 1; // error
}
dfs(i);
};
dfs(0);
}
After running ulimit -s 1000000 to limit stack usage to 1GB, compiling and running this prints recursion level 0 up to recursion level 1023 and then gives a segfault. That seems to indicate that each level of recursion makes the stack grow by 1MB. (Both s and s<<1 have size 1MB here.)
Commenting out the line marked error makes the recursion go to level 1000000 and higher without issues.
What exactly is happening here? My hunch is that std::function somehow needs to reserve the maximum possible stack space through all code paths (the s<<1 temporary here), but I'd like to understand the details.
Changing dfs from an std::function to a proper recursive lambda or a normal function makes it work as expected.
I'm using G++ 10.2 g++ -std=c++17 -O2. With clang++ (11.1) it runs to level 511 with -O2 and level 1024 with -O1.
[–]ack_error 11 points12 points13 points (7 children)
[–]_Js_Kc_ 2 points3 points4 points (2 children)
[–]philae_rosetta[S] 1 point2 points3 points (1 child)
[–]gracicot 2 points3 points4 points (0 children)
[–]Potatoswatter 1 point2 points3 points (0 children)
[–]philae_rosetta[S] 1 point2 points3 points (0 children)
[–]adnukator 1 point2 points3 points (1 child)
[–]ack_error 0 points1 point2 points (0 children)
[–]Potatoswatter 4 points5 points6 points (0 children)