I'm learning gdb debugger and one question I cannot answer is:
new function calls result in additional stack frames allocated for them and call stack grows downward; stack frame is deallocated and returned to unused memory. is it possible that a frame in the middle of the stack be deleted and returned to memory? can go to statement or longjmp function make this happen?
Many thanks.
No, frame in the middle can not be deleted, because call stack is a stack. Only a stack pointer pointing to top of a stack (and optionally frame pointer that points to beginning of last frame) are maintained. As frame is "deleted" (return from function), only these pointers are moved and next allocated frame will overwrite this.
This thread (and few others) explains why longjmp can't violate this behavior. In short, setjmp stores frame position, but if frame itself has been overwritten, this fails.
And goto can't jump to a different function.
Related
I have read that each function invocation leads to pushing of a stack frame in the global call stack and once the function call is completed the call stack is popped off and the control passes to the address that we get from the popped of stack frame. If a called function calls on to yet another function, it will push another return address onto the top of the same call stack, and so on, with the information stacking up and unstacking as the program dictates.
I was wondering what's at the base of global call stack in a C or C++ program?
I did some searching on the internet but none of the sources explicitly mention about it. Is the call stack empty when our program starts and only once a function is called, the call stack usage starts? OR Is the address where main() function has to return, gets implicitly pushed as the base of our call stack and is a stack frame in our call stack? I expect the main() would also have a stack frame in our call stack since we are always returning something at end of our main() function and there needs to be some address to return to. OR is this dependent on compiler/OS and differs according to implementation?
It would be helpful if someone has some informative links about this or could provide details on the process that goes into it.
main() is invoked by the libc code that handles setting up the environment for the executable etc. So by the time main() is called, the stack already has at least one frame created by the caller.
I'm not sure if there is a universal answer, as stack is something that may be implemented differently per architecture. For example a stack may grow up (i.e. stack position pointer value increases when pushing onto the stack) or grow downwards.
Exiting main() is usually done by calling an operating function to indicate the program wishes to to terminate (with the specified return code), so I don't expect a return address for main() to be present on the stack, but this may differ per operating system and even compiler.
I'm not sure why you need to know this, as this is typically something you leave up to the system.
First of all, there is no such thing as a "global call stack". Each thread has a stack, and the stack for the main thread is often looking quite different from the thread of any thread spawned later on. And mostly, each of these "stacks" is just an arbitrary memory segment currently declared to be used as such, sub-allocated from any arbitrary suitable memory pool.
And due to compiler optimizations, many function calls will not even end up on the stack, usually. Meaning there isn't necessarily a distinguishable stack frame. You are only guaranteed that you can reference variables you put on the stack, but not that the compiler must preserve anything you didn't explicitly reference.
There is not even a guarantee that the memory layout for your call stack must even be organized in distinguishable frames. Function pointers are never guaranteed to be part of the stack frame, just happens to be an implementation detail in architectures where data and function pointers may co-exist in the address space. (As there are architectures which require return addresses to be stored in a different address space than the data used in the call stack.)
That aside, yes, there is code which is executed outside of the main() function. Specifically initializers for global static variables, code to set up the runtime environment (env, call parameters, stdin/stdout) etc.
E.g. when having linked to libc, there is __libc_start_main which will call your main function after initialization is done. And clean up when your main function returns.
__libc_start_main is about the point where "stack" starts being used, as far as you can see from within the program. That's not actually true though, there has already been some loader code been executed in kernel space, for reserving memory for your process to operate in initially (including memory for the future stack), initializing registers and memory to well defined values etc.
Right before actually "starting" your process, after dropping out of kernel mode, arbitrary pointers to a future stack, and the first instruction of your program, are loaded into the corresponding processor registers. Effectively, that's where __libc_start_main (or any other initialization function, depending on your runtime) starts running, and the stack visible to you starts building up.
Getting back into the kernel usually involves an interrupt now, which doesn't follow the stack either, but may just directly access processor registers to simply swap the contents of the corresponding processor registers. (E.g. if you call a function from the kernel, the memory required by the call stack inside the function call is not allocated from your stack, but from one you don't even have access to.)
Either way, everything that happens before main() is called, and whenever you enter a syscall, is implementation dependent, and you are not guaranteed any specific observable behavior. And messing around with processor registers, and thereby alternating the program flow, is also far outside defined behavior as far as a pure C / C++ run time is concerned.
Every system I have seen, when main() is called a stack is setup. It has to be or just declaring a variable inside main would fail. A stack is setup once a thread or process is created. Thus any thread of execution has a stack. Further in every assembly language i know, a register or fixed memory location is used to indicate the current value of the stack pointer, so the concept of a stack always exists (the stack pointer might be bad, but stack operations always exist since they are built into the every mainstream assembly language).
I have a pool of threads that have explicitly allocated stacks (i.e., using pthread_attr_setstack).
Is it possible to use something like gnulib's backtrace & backtrace_symbols on this stack?
Thanks.
backtrace() returns a backtrace for the calling program, in the array
pointed to by buffer.
Therefore yes, it does not care where the stack was allocated. You simply call it from the target thread and the stack information is implicit in the current stack pointer.
If you want to backtrace another thread (other than the one that's running) that's trickier. For one thing, it may be running, which would make all attempts to backtrace subject to races. But for another, I don't think there's any standard way for the current stack pointer (which is where the trace should start) to be made visible to another thread. Without that information you can't start the trace, because the base of the stack isn't really enough information.
(ptrace can get the current register values. This is the system call used by debuggers. It will be quite disruptive, though)
I came across the following paragraph while reading bruce eckel..where he was trying to explain why its not safe for function to return value on stack
Now imagine what would happen if an ordinary function tried to return values on the stack
.you can,t touch any part of the stack that's above the return address,so the function would have to push the values below the return address.But when the assembly language return is executed ,the stack pointer must be pointing to the return address(or right below it depending on your machine),so right before the RETURN ,function must move the stack pointer up,thus clearing of all the local variables.If you are trying to return values on the stack below the return address,you become vulnerable at the moment because an interrupt could come along.The ISR would come the stack pointer down to hold its return address and its local variables and overwrite your return value
would you like to help me for comprehend the bold italic text?
Suppose that you have the following call stack somewhere in your application:
Main routine
Function1's local variables
Function2's local variables <-- STACK POINTER
In this case main calls function1, and function1 calls function2.
Now suppose that function2 calls function3, and the return value of function3 is returned on the stack:
Main routine
Function1's local variables
Function2's local variables
Function3's local variables, including the return value <-- STACK POINTER
Function3 stores the return value on the stack, and then returns. Returning means, decreasing the stack pointer again, so the stack becomes this:
Main routine
Function1's local variables
Function2's local variables <-- STACK POINTER
You see, function3's stack frame is not here anymore.
Well, actually I lied a bit. The stack frame is still there:
Main routine
Function1's local variables
Function2's local variables <-- STACK POINTER
Function3's local variables, including the return value
So it seems safe to still access the stack to get the return value.
But, if there is an interrupt AFTER function3 has returned, but BEFORE function2 get's the return value from the stack, we get this:
Main routine
Function1's local variables
Function2's local variables
Interrupt function's local variables <-- STACK POINTER
And now the stack frame is really overwritten, and the return value that we desperately needed has gone.
That's why returning a return value on the stack is not safe.
The problem is similar to the one shown in this simple piece of C code:
char *buf = (char *)malloc(100*sizeof(char *));
strcpy (buf, "Hello World");
free (buf);
printf ("Buffer is %s\n",buf);
Most of the times, the memory that was used for buf will still have the contents "Hello World", but it can go horribily wrong if someone is able to allocate memory after free has been called, but before printf is called. One such example is in multi-threaded applications (and we already encountered this problem internally), like shown here:
THREAD 1: THREAD 2:
--------- ---------
char *buf = (char *)malloc(100);
strcpy (buf, "Hello World");
free (buf);
char *mybuf = (char *)malloc(100);
strcpy (mybuf, "This is my string");
printf ("Buffer is %s\n",buf);
The printf is Thread 1 may now print "Hello World", or it may print "This is my string". Anything can happen.
He is just trying to explain why you shouldn't return a pointer or reference to a local variable. Because it disappears as soon as the function returns!
Exactly what happens at the hardware level isn't that important, even if it might explain why the value sometimes seems to still be there and sometimes not.
When you call a function that has pass-by-stack arguments, those arguments get pushed onto the stack. When the function returns, that bit of stack memory it was using is released. Immediately thereafter, it's unsafe to access what was in those stack values, because something else may have overwritten them.
Let's say we're on a cpu where the stack pointer is kept in a register called SP, and it grows "upwards".
Your code is chugging along and comes to a function call. At this point, we'll say SP is 100.
The function is called, and your function takes two single byte arguments. Those two bytes worth of arguments get pushed onto the stack, and... and this is the important part - the address of the code from which you called the function (let's say it's 4bytes). Now SP is 106. The address to return to is at SP=100, and your two bytes are at 104 and 105.
Let's say the function modifies one of those arguments (SP=105) as a way to return the modified value
The function returns, the stack snaps back to where it was (SP=100), and continues on.
In a perfect world, there's nothing else going on in the system and your program has absolute control over the CPU... Until you do something else that requires the stack, that SP=105 value will stay there "forever".
However, with interrupts, there's no guarantees that something else won't come up. let's say a hardware interrupt hits your app. This means an immediate jump to the interrupt servicing routine, so the current address of where the CPU was when the interrupt hit gets pushed onto the stack (4 bytes), now SP is 103. Let's say this ISR calls other subroutines, which means more return addresses get pushed onto the stack. So now SP is 107... your original 105 value has no been overwritten.
eventually these ISRs will return, control goes back to your code, and SP is 100 again... your app tries to retrieve that SP=105 value, blissfully unaware that it got trashed by the ISR, and now you're working with bad data.
The most important part of that paragraph is:
If you are trying to return values on
the stack below the return address (...)
In other words, don't return pointers to data that is only valid within the scope of that function.
This was probably something you had to worry about before C standardized how a function returned a struct by value. Now, it's part of the C99 standard (6.8.6.4) and you shouldn't worry about it.
And return by value is fully supported in C++ for a while now. Otherwise, many STL implementation details would simply not work properly.
During a call to function B() from function A(), B() allocates a 100-char array and fills it several times, including once with a 101-character string and once with a 110 character string. This is an obvious mistake.
Later, function A() tries to access completely unrelated int variable i, and a segmentation fault occurs.
I understand why the buffer overrun occurs, but why do I get a segmentation fault when I access this integer? Why is it that I don't simply get garbage data?
A buffer overrun may clobber a previously saved version of the frame pointer on the stack.
When the function returns, this corrupt version is loaded into the frame pointer register, causing the behavior you describe.
Wikipedia's page contains a figure and definitions.
When A() calls B(), B's preamble instructions save A's frame pointer—the location on the stack where A keeps local variables, before replacing it with B's own frame pointer. It looks like this:
When B overruns its local variables, it messes up the value which will be reloaded into the frame pointer. This is garbage as a frame pointer value, so all of A's local variables are trashed. Worse, future writes to local variables are messing with memory belonging to someone else.
The most likely explanation from you description is that the overrun in B corrupts the saved frame pointer on the stack for A. So after B returns, A has garbage in its frame pointer and crashes when it tries to access a local variable.
If you're accessing i through a pointer, then the problem is the pointer is garbage.
It is important to remember that you allocate enough memory plus one for the nul terminating character (Astute readers will point out this nul, that is primarily there for a reason - a nul with one 'l' is '\0' [Thanks Software Monkey for pointing out an error!], a null with two 'l' is a pointer pointing to nothing).
Here's an example of how a seg fault can occur
int main(int argc, char **argv){
int *x = NULL;
*x = 5;
// boom
}
Since x is a pointer and set to null, we attempt to dereference the pointer and assigning a value to it. A guaranteed way of generating a segmentation fault.
There is an old trick available in that you can actually trap the seg fault and get a stack trace, more common on unix environment, by setting up a signal handler to trap a SIGSEGV, and within your signal handler invoke a process like this:
char buf[250];
buf[0] = '\0';
sprintf(buf, "gdb -a %d | where > mysegfault.txt", getpid());
system(buf);
This attaches the currently executing C program and shells out to the debugger and attaches itself to it, the where part of it shows the stack trace of the offending line that caused the seg fault and redirects the output to a file in the current directory.
Note: this is implementation defined, depending on the installation, under AIX, the gnu debugger is present and hence this will work, your mileage may vary.
Hope this helps,
Best regards,
Tom.
If I've registered my very own vectored exception handler (VEH) and a StackOverflow exception had occurred in my process, when I'll reach to the VEH, will I'll be able to allocate more memory on the stack? will the allocation cause me to override some other memory? what will happen?
I know that in .Net this is why the entire stack is committed during the thread's creation, but let's say i'm writing in native and such scenario occurs ... what will i able to do inside the VEH? what about memory allocation..?
In the case of a stack overflow, you'll have a tiny bit of stack to work with. It's enough stack to start a new thread, which will have an entirely new stack. From there, you can do whatever you need to do before terminating.
You cannot recover from a stack overflow, it would involve unwinding the stack, but your entire program would be destroyed in the progress. Here's some code I wrote for a stack-dumping utility:
// stack overflows cannot be handled, try to get output then quit
set_current_thread(get_current_thread());
boost::thread t(stack_fail_thread);
t.join(); // will never exit
All this did was get the thread's handle so the stack dumping mechanism knew which thread to dump, start a new thread to do the dumping/logging, and wait for it to finish (which won't happen, the thread calls exit()).
For completeness, get_current_thread() looked like this:
const HANDLE process = GetCurrentProcess();
HANDLE thisThread = 0;
DuplicateHandle(process, GetCurrentThread(), process,
&thisThread, 0, true, DUPLICATE_SAME_ACCESS);
All of these are "simple" functions that don't require a lot of room to work (and keep in mind, the compiler will inline these msot likely, removing a function call). You cannot, contrarily, throw an exception. Not only does that require much more work, but destructors can do quite a bit of work (like deallocating memory), which tend to be complex as well.
Your best bet is to start a new thread, save as much information about your application as you can or want, then terminate.
No, you can't allocate memory in vectored exception handler.
MSDN says it explicitly:
"The handler should not call functions that acquire synchronization objects or allocate memory, because this can cause problems. Typically, the handler will simply access the exception record and return."
Stacks need to be contiguous, so you can't just allocate any random memory but have to allocate the next part of the address space.
If you are willing to preallocate the address space (i.e. just reserve a range of addresses without actually allocating memory), you can use VirtualAlloc. First you call it with the MEM_RESERVE flag to set aside the address space. Later, in your exception handler you can call it again with MEM_COMMIT to allocate physical memory to your pre-reserved address space.