Msg/StackDeallocatedParentFrame: Difference between revisions

From CPUlator Wiki

< Msg
Created page with "A stack frame is a region of memory used by an executing function. When calling a function, the child function's stack frame is at a lower address than the caller's stack fram..."
 
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 6: Line 6:
==== ARMv7 ====
==== ARMv7 ====


<syntaxhighlight line lang="Asm">
<syntaxhighlight line lang="Asm" highlight="7">
.global _start
.global _start
_start:
_start:
mov sp, #0x1000 // Initialize SP to something sane     
mov sp, #0x1000 // Initialize SP to something sane     
    bl Func
bl Func
      
      
Func:
Func:
add sp, #4 // Deallocated 4 bytes of the caller's stack frame
add sp, #4 // Deallocate 4 bytes of the caller's stack frame
    sub sp, #4 // Can't do this even if the operation is reverted
sub sp, #4 // Can't do this even if the operation is reverted
    bx lr
bx lr
</syntaxhighlight>
</syntaxhighlight>
==== Nios II ====
==== Nios II ====
<syntaxhighlight line lang="Asm">
<syntaxhighlight line lang="Asm" highlight="7">
.global _start
.global _start
_start:
_start:
movi sp, 0x1000 # Initialize SP to something sane     
movi sp, 0x1000 # Initialize SP to something sane     
    call Func
call Func
      
      
Func:
Func:
addi sp, sp, 4 # Deallocated 4 bytes of the caller's stack frame
addi sp, sp, 4 # Deallocate 4 bytes of the caller's stack frame
    subi sp, sp, 4 # Can't do this even if the operation is reverted
subi sp, sp, 4 # Can't do this even if the operation is reverted
     ret
ret
</syntaxhighlight>
==== MIPS ====
<syntaxhighlight line lang="Asm" highlight="7">
.global _start
_start:
li $sp, 0x1000 # Initialize SP to something sane   
jal Func
      
Func:
addiu $sp, $sp, 4 # Deallocate 4 bytes of the caller's stack frame
addiu $sp, $sp, -4 # Can't do this even if the operation is reverted
jr $ra
</syntaxhighlight>
</syntaxhighlight>


Line 35: Line 47:


=== Debugging ===
=== Debugging ===
* Normally, all stack pointer manipulations are matched: Decrease the stack pointer when entering a function, and increasing the stack pointer immediately before returning. Check for stack pointer operations (push and pop) that are mismatched.
* Normally, all stack pointer manipulations are matched: decrease the stack pointer when entering a function, and increase the stack pointer immediately before returning.  
* Carefully trace through any operations that change the stack pointer. Make sure they're all matched (every decrement is matched by an increment of the same amount). Ensure that the function prologue and epilogue only execute once (not accidentally part of a loop).
* The two places where stack pointer manipulations often occur are at the function prologue and epilogue, and allocating and deallocating arguments passed on the stack when calling a function. These operations are all matched. If your function uses the stack pointer for other purposes, this is an easy source of bugs.
 
=== Implementation ===
The simulator identifies idiomatic call and return instructions executed at runtime. It records the values of registers when executing call instructions, and compares the current stack pointer to the stack pointer at the beginning of the function. This warning is generated at the instruction that modifies the stack pointer.


{{DisableMsg|SP moved beyond current stack frame}}
{{DisableMsg|SP moved beyond current stack frame}}

Latest revision as of 04:14, 17 March 2019

A stack frame is a region of memory used by an executing function. When calling a function, the child function's stack frame is at a lower address than the caller's stack frame. New stack space is allocated by decrementing the stack pointer, and stack space is deallocated by incrementing the stack pointer. However, a function should not deallocate the parent function's stack frame. In other words, the stack pointer should never be greater than the value at the beginning of the function. This warning tells you that the stack pointer has increased past the value it had at the beginning of the current function.

This is a more stringent requirement than simply requiring the stack pointer to be restored to its original value at the end of the function. Because an interrupt can occur at any moment, if the stack pointer increases beyond the current stack frame (deallocating the parent's stack frame) even momentarily, the parent function may lose some of its stack values because an interrupt handler may have executed and used the "free" stack space below the stack pointer.

Example

ARMv7

.global _start
_start:
	mov sp, #0x1000			// Initialize SP to something sane    
	bl Func
    
Func:
	add sp, #4				// Deallocate 4 bytes of the caller's stack frame
	sub sp, #4				// Can't do this even if the operation is reverted
	bx lr

Nios II

.global _start
_start:
	movi sp, 0x1000			# Initialize SP to something sane    
	call Func
    
Func:
	addi sp, sp, 4			# Deallocate 4 bytes of the caller's stack frame
	subi sp, sp, 4			# Can't do this even if the operation is reverted
	ret

MIPS

.global _start
_start:
	li $sp, 0x1000			# Initialize SP to something sane    
	jal Func
    
Func:
	addiu $sp, $sp, 4		# Deallocate 4 bytes of the caller's stack frame
	addiu $sp, $sp, -4		# Can't do this even if the operation is reverted
	jr $ra

In the above examples, the stack pointer is initialized to 0x1000. The child function Func can allocate and deallocate stack space below the stack pointer (currently 0x1000). It is not allowed to deallocate the parent's stack frame. The child function here attempts to move the stack pointer to 0x1004. This results in the warning: Stack pointer moved beyond current stack frame. sp at beginning of current function was 00001000

The message also reminds you that the stack pointer was 0x1000 at the beginning of the function, and that the stack pointer has increased beyond this point (to 0x1004).

Debugging

  • Normally, all stack pointer manipulations are matched: decrease the stack pointer when entering a function, and increase the stack pointer immediately before returning.
  • Carefully trace through any operations that change the stack pointer. Make sure they're all matched (every decrement is matched by an increment of the same amount). Ensure that the function prologue and epilogue only execute once (not accidentally part of a loop).
  • The two places where stack pointer manipulations often occur are at the function prologue and epilogue, and allocating and deallocating arguments passed on the stack when calling a function. These operations are all matched. If your function uses the stack pointer for other purposes, this is an easy source of bugs.

Implementation

The simulator identifies idiomatic call and return instructions executed at runtime. It records the values of registers when executing call instructions, and compares the current stack pointer to the stack pointer at the beginning of the function. This warning is generated at the instruction that modifies the stack pointer.

Disabling this message

This debugging check can be disabled in the Debugging Checks section of the Settings box: SP moved beyond current stack frame.