Struct and enum accessors take a large amount of stack space

Thanks for confirming the issue and suggestion for indirect. I didn't know indirect can be used for general purpose like this. Yes, it works well. The stack size is 56K now.

BTW, I did an experiment before I made the indirect change. I modified my code to remove the enum in question but kept the payload type, which is a struct of 1K size. I find that also greatly reduces the stack size. It seems enum is more likely to have stack size issue than struct.

Yes, that's the reason.

I see your point. It's an estimation (though very useful). Chances are the initial 24k stack memory are not completely used. That explains why print(1) doesn't cause vmmap output change. BTW, pagesize shows macOS uses 4k page size on Intel CPU.

I didn't know about outlined function either. The concept is simple. See here.

Sorry about the "multiple versions" confusion. It was my hypothesis, based on the observation that stack size grown gradually and finally overflowed. I tried to prove it and thought the two versions I posted were for the same enum, but they weren't. I investigated this today and finally figured out what happened. Since this is a known issue and we have solutions to avoid it, the following details are just for fun.

  • For a specific enum, there seems to be just one piece of code for its accessor. As the code in my original post shown, it may have large frame size.

  • There is a 4K stack guard space immediately after each stack. Unfortunately, due to the big frame size of enum accessor and the way how it works (it seems that while accessor reserves a large amount of space, it doesn't necessarily uses all of them), the stack guard fails to catch the overflow issue, because the accessor doesn't necessarily access that 4k address space.

  • As a result, although there is overflow, the code doesn't crash because it is using another thread's stack! The code may continue to run until it finally tries to access an invalid virtual address (vmmap shows there are unallocated virtual address range between two stacks sometimes). Otherwise the code completes successfully (although it shouldn't). I believe this explains the random behaviors I observed while I tested the issue these days.

2 Likes