Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any way to force local variables to the stack in 64bit VC application

When a 64 bit VC 2005 application is compiled with optimization turned on, it is not possible to see all local variables in a crash dump file. In many cases, the local variables or parameters are stored in registers instead of on the stack. Subsequent calls to other functions, such as error handling functions, will sometimes overwrite those values. This makes it difficult to trace the cause of the problem. Is there a way to force local variables and/or parameters to the stack at run time?

Turning off the optimization is one way but that makes application slow, and it is generally not a good idea for the release build. I am hoping that there is a run time call that will dump all local variables and/or registry somewhere. If there is such function, we can then call the function before calling the error logging function and will hopefully be able to see more local variable on the stack.

-- Alex

like image 315
Alex W Avatar asked Feb 10 '10 20:02

Alex W


People also ask

Do local variables go on the stack?

The stack is used for dynamic memory allocation, and local variables are stored at the top of the stack in a stack frame. A frame pointer is used to refer to local variables in the stack frame.

How are variables saved on the stack?

When a new local variables is declared, more stack memory is allocated for that function to store the variable. Such allocations make the stack grow downwards. After the function returns, the stack memory of this function is deallocated, which means all local variables become invalid.

Why are local variables stored in stack?

When a function is called the local variables are stored in a stack, and it is automatically destroyed once returned. A stack is used when a variable is not used outside that function. It allows you to control how memory is allocated and deallocated.


2 Answers

I think you're seeing something else. Most common calling conventions on x86 pass arguments the function arguments on the stack. But the x64 calling convention is different, it is similar to __fastcall on x86, it passes the first 4 function arguments in registers (rcx, rdx, r8 and r9). If the function is non-trivial, the compiler generates code to save those registers on the stack frame right away.

Unfortunately, the debugger isn't smart enough to know about the saved register locations. It displays the register value in the call stack, a value that almost always has changed. You can technically dig the argument value out of the stack frame yourself, but you really, really want to have to do this. In optimized code it is an offset from rsp, not rbp, and the stack pointer value has changed as well.

I haven't found any good workaround for this yet. Looking forward to improvements in the VS2010 debugger, no idea if this was addressed.

like image 167
Hans Passant Avatar answered Oct 14 '22 15:10

Hans Passant


If you take the address of a variable, the compiler will be forced to allocate space for it on the stack, so you could write a little macro.

#ifdef DEBUG
 #define FORCE_ON_STACK(var)  void * p##var##_dummy = (void *)&var
#else
 #define FORCE_ON_STACK(var)  (void)0 // eat the ;
#endif

The compiler still might be lazy about keeping the value on the stack in sync with the registers in some cases. Also keeping arguments in registers is an important optimization which this will at least partly defeat, so this will impact performance somewhat.

like image 29
John Knoeller Avatar answered Oct 14 '22 14:10

John Knoeller