How code refactoring can fix stack overflow error?

Feb 2016

How code refactoring can fix stack overflow error?

tl;dr: A very long C++ function with multiple local variables, even if they are not very big and they are placed in separate scopes, can reserve as much as hundreds of kilobytes of stack frame, causing "Stack Overflow" even without bugs like infinite recursion. So you better split your long functions into shorter ones.

Can refactoring (or the lack of thereof) cause application crashes? If we understand refactoring as changes in code layout without changing its logic, we might think that it's just the matter of readability and unreadable code increases chances of introducing bugs. But here is a story in which refactoring actually fixed a bug.

Long time ago in a software project far far away, there was a bug submitted telling that the application crashes with "Stack Overflow" message. It was a Windows app, developed in C++ using Visual Studio. I thought: - I can handle that, it should be easy! Every beginner/intermediate programmer knows about the call stack and surely seen this error at least once when accidentally caused infinite recursion in his code. So my first idea was that infinite recursion happens because of some logical error in the code (that should be easy to fix) or some unfortunate, invalid input data (that should be validated for safety before usage).

As it turned out, this was not the case. After setting up all the test environment and catching the crash in Visual Studio debugger, I looked at Call Stack and noticed that it looks quite normal. Sure the call depth was significant (as for C++, I'm not talking about Java here ;) and there was even some recursion, but 20 or 30 functions is not that much. The stack ended with a call to non-recursive function that seemed correct, so it was not the recursion that caused stack overflow.

My second idea was that some of these functions allocate some big objects (like arrays) by value, as local variables on the stack and this causes the stack to grow too big. I reviewed code of the functions that I found on the stack and used "Immediate Window" panel to quickly check sizeof(xxx) of variables or their types when they used some class, but I didn't find anything particularly big. Local variable sizes varied from few bytes to at most several hundred bytes and I couldn't find any big arrays defined in these functions. I also fetched address of some local variable in a function near the bottom of the stack (which looks like 0x000000000009a370), address of a parameter from the function at the top of the stack and subtracted them to see how big the stack grown over all these calls. The result was around 50 KB - not that much.

My third idea was to check maximum size of the stack. It is 1 MB by default, but it can be changed in Visual Studio project settings, in Linker > System tab, as "Stack Reserve Size" parameter. I check my project and I found this parameter not changed from its default value.

OK, now this became more difficult than I thought. After many debugging sessions, where I looked at various pointers, addresses and numbers trying to spot some memory override, stack corruption, out-of-bounds indexing etc., I finally opened "Disassembly" and "Registers" panels. I'm not a fan of such low level stuff, so it took me some time and few Google queries to understand these RSP, RBP registers and make sense of some x86-64 opcodes. While debugging step-by-step in the assembly, I found something interesting. At the beginning of my function, there was a call to mysterious function __chkstk and the crash occurred inside it. That was a clue I could use to ask Google what this all means. I found this: Description of the stack checking for Windows NT-based applications and this: What is the purpose of the _chkstk() function? These articles say that as the stack grows, next 4 KB pages are reserved. Each next page is allocated by the system on first "touch". I could actually see in my debugger that functions which need less than 1 page (4096 B = 1000h) have an instruction at the beginning similar to this:

sub         rsp,0A9h

While my debugged function had this instead:

mov         eax,26B29h
call        __chkstk (018104AA00h)
sub         rsp,rax

The articles say that when reserving more than one page of stack memory, this function must be called to loop over addresses with 4 KB step and "touch" each page. This is really what it does:

--- f:\dd\vctools\crt\crtw32\startup\amd64\chkstk.asm ---
sub         rsp,10h
mov         qword ptr [rsp],r10
mov         qword ptr [rsp+8],r11
xor         r11,r11
lea         r10,[rsp+18h]
sub         r10,rax
cmovb       r10,r11
mov         r11,qword ptr gs:[10h]
cmp         r10,r11
jae         cs10+10h (018104AA40h)
and         r10w,0F000h
lea         r11,[r11-1000h]
mov         byte ptr [r11],0
cmp         r10,r11
jne         cs10 (018104AA30h)
mov         r10,qword ptr [rsp]
mov         r11,qword ptr [rsp+8]
add         rsp,10h

Key sentence of the second linked article seems to be: "The parameter in rax is size of data you want to add." In my case, eax is set to 26B29h = 158505. Wait, what?! This is more than 150 KB! Is it really how much of the stack the function needs?!

It was finally the right conclusion. The function was more than 3000-lines long, with lots of nested conditions and all kinds of stuff, but mostly an all-encompassing switch with dozens of different cases. I refactored it, extracting code from under each case to a separate function. This fixed the "Stack Overflow" crash.

Apparently if you have a long function and define a lot of local variables, even if they are not particularly big and they are placed inside separate scopes like if-s or switch case-s, the function may need as much as 150 KB of stack frame, at least in Debug configuration. This can cause crash with "Stack Overflow" message even without infinite recursion or bugs like that. So please keep this in mind as additional argument for refactoring your code as soon as you see the need for it.

Comments (2) | Tags: visual studio c++ | Author: Adam Sawicki | Share


2016-03-25 03:43:50
If you are happy temperament, I have a song, dance with your favorite look; if you rife, I will become a cloud, falling some peerless situation; for this flower Dimei under Xu, Xu next stop for this cloud, let that drop of rain touched that masterpiece encounter; not to ask, in the southern misty rain ink, or vegetation desolate Saibei only hope that you read in conjunction rain Partly farming, leisure together Immersió listen to the birds, over the days together with ordinary water .

If grinding moonlight, the wind pen, next month before it flowers, pen years water volume; with traces breeze atmosphere, clouds, and in a paper by the recollection of old books you warm; make clear water in Qiannian landscape outside, waiting for the moon and new moon; quietly spend the joy of silence, do not ask how changes of marshes, how rotary years, the only place in the bridges for you as I ended classic.

Life would like to make the dust of a lotus, the mountain waiting for a ride a water ride with a window the bright window, the sun was warm embrace, Wan Wan in a new Green Mile, this life filled with love; make a colorful in full bloom throughout the spring, to meet a beautiful painting on the successful!

A tea seats bed, a pillow Scrolls fine ponder. This is a simple literature, this is the classic psychic, regardless of gem material, regardless of the net worth of the poor, because the share of hazy love, love deep into the soul.

This literary love, love this millennia-old Chinese soul of the wind. Or vigorous, soul-stirring, like Longyou song marsh, Huang Fei nine days; or single elevation grid, noble Aoshuang, like Pine Valley Health, Xia Ying Cheng Tong; or want to go think, therefore, become lazy Ke Zhou, Shen round like the moon and stars, the rivers into the ocean; or plaintive blurred, cold hesitation, like Su Yi impermanence, cold feast next month. Let him how Mind, only for the love affair Everlasting, the text from the heart Think that summer, a column Chen Xiang a cool pillow, which is the roots of what you need to make tea cooking wine, Hongxiutianxiang just hand poetry twos Bliss half a day can tolerate you wander. Static water body, Shen soul dream, it is only a few clouds color country Pitt, rivers and mountains, jade group. Do not ask bustling past, gone; do not ask flowery Meijuan, Homecoming, heart like hanging a mirror, according to Italian Bodhi station.

Three thousand Red ink, as are cold-blooded bustling paper, into a word discretion. Five thousand years of calligraphy love this, love flames smoke sand which contained five thousand years. Regardless of the time, and regardless of age just enthusiastic, you can play the most beautiful music in the soul. Born This paper declared the era of thick ink, it is really Qing Sansei lucky, I have the edge. Not to think about what flat Zeze, do not repair what suppression suppression triumphantly, play with my ink, paper and ink, ink into song. Wenbujiadian, Tengjiao Qifeng. Three feet of white Xuan, lead me thousand words mantra; five bucket heavy color, any time I wanton chapters. Wenqi thunder, put pen to paper to stay hui, was widely bully Zimei, bearing pressure Bai.
2016-03-29 09:46:03
<a href=>&#22806;&#36865;&#33590;</a>
<a href=>&#21488;&#21271;&#22806;&#36865;&#33590;</a>
<a href=>&#20813;&#36027;&#25104;&#20154;&#24433;&#29255;</a>
<a href=>&#22806;&#32004;</a>
<a href=>&#22806;&#36865;&#33590;&#33674;</a>
<a href=>&#20813;&#36027;&#25104;&#20154;&#38651;&#24433;</a>
<a href=>&#21488;&#21271;&#22806;&#36865;&#33590;&#33674;</a>
<a href=>&#21451;&#36948;&#26053;&#34892;&#31038;&#34218;&#36039;</a>
<a href=>&#25104;&#20154;&#25991;&#23416;</a>
<a href=>&#22806;&#36865;&#33590;</a>
<a href=>&#33590;&#35338;</a>
<a href=>&#25588;&#20132;</a>
<a href=>&#21322;&#22871;</a>
Idsgaklj.<a href=>&#20276;&#36938;</a>
<a href=>&#20840;&#22871;</a>
<a href=>&#25214;&#23567;&#22992;</a>
<a href=>&#20840;&#22871;</a>
<a href=>&#25033;&#21484;</a>
<a href=>&#22806;&#36865;&#33590;</a>
<a href=>&#25588;&#20132;</a>
<a href=>&#22806;&#36865;&#33590;</a>
<a href=>&#21483;&#23567;&#22992;</a>
<a href=>&#20840;&#22871;&#26381;&#21209;</a>
<a href=>&#22806;&#36865;&#33590;</a>
<a href=>&#25214;&#33590;</a>
<a href=>&#22806;&#36865;</a>
<a href=>&#25588;&#20132;</a>
<a href=>&#19968;&#22812;&#24773;</a>
<a href=>&#25588;&#20132;</a>
<a href=>&#25588;&#20132;</a>
<a href=>&#24503;&#24030;&#25778;&#20811;&#36938;&#25138;</a>
<a href=>&#21338;&#24328;&#36938;&#25138;</a>
<a href=>&#21338;&#24328;&#36938;&#25138;</a>
<a href=>&#30334;&#23478;&#27138;</a>
<a href=>bar&#27700;&#26524;&#30436;&#36938;&#25138;</a>
<a href=>&#21338;&#24328;&#36938;&#25138;</a>

Post comment

Nick *
Your name or nickname
Your contact information (optional, will not be shown)
Text *
Content of your comment
Calculate *
(* - required field)
STAT NO AD [Stat] [Admin] [STAT NO AD] [pub] [Mirror] Copyright © 2004-2016 Adam Sawicki
Copyright © 2004-2016 Adam Sawicki