Suppose your application has the following call stack:
- Basic procedure
- Local variables Function1
- Local variables Function2 <- STACK POINTER
In this case, the main calls to function1, and function1 calls function2.
Now suppose that function2 calls function3, and the return value of function3 is returned to the stack:
- Basic procedure
- Local variables Function1
- Local variables Function2
- Function3 local variables including return value <- STACK POINTER
Function 3 stores the return value on the stack, and then returns. The returned tool again decreases the stack pointer, so the stack becomes the following:
- Basic procedure
- Local variables Function1
- Local variables Function2 <- STACK POINTER
It is clear that the frame of the function3 frame no longer exists here.
Well, actually I lied a little. The stack frame still exists:
- Basic procedure
- Local variables Function1
- Local variables Function2 <- STACK POINTER
- Function3 local variables including return value
Thus, to get the return value, it seems safe to access the stack.
But, if there is an AFTER interrupt function returned, but before function2 receives the return value from the stack, we get the following:
- Basic procedure
- Local variables Function1
- Local variables Function2
- Local variables of the interrupt function <- STACK POINTER
And now the stack frame is really overwritten, and the return value that we desperately need is gone.
That is why returning the return value on the stack is unsafe.
The problem is similar to the one shown in this simple C code snippet:
char *buf = (char *)malloc(100*sizeof(char *)); strcpy (buf, "Hello World"); free (buf); printf ("Buffer is %s\n",buf);
In most cases, the memory used for buf will still contain the contents of "Hello World", but it can go horribly wrong if someone can allocate memory after calling free, but before calling printf. One such example is in multi-threaded applications (and we have already encountered this problem internally), as 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);
printf is Thread 1, now you can print "Hello World", or it can print "This is my line." Everything can happen.