AVR Stack Overflow Possible?

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When ever a interrupt or subroutine call is executed the return address is kept on the stack, the stack pointer is decremented.

Is it possible for the stack pointer to decrement below 0x60?
Or what happens in the case of an stack overflow?

Thx

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wauschi wrote:
Is it possible for the stack pointer to decrement below 0x60?
Or what happens in the case of an stack overflow?
Yes, it is possible, that SP will decrement below 0x60 (on the newer AVR's memory mapped registers will go up 0xff).
The result of this overflow is not predictable (rcall/interrupt will modify the register, ret/reti will return to a wrong address.
/Martin.

/Martin.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The stack pointer will happily decrement below 0x60. It will start modifying the I/O registers.

A quick simulation in AVR Studio seems to indicate that the SREG, SPH, and SPL registers will be unaffected by an attempt to PUSH something to their locations. However, all the other I/O locations will be treated as if they were just another location in RAM. And you'll see crazy things start happening in your AVR's peripherals.

When the stack pointer reaches 0x0000, it will wrap-around to the top of the data memory space and start writing to the top of RAM again.

There is no hardware protection against the stack writing to I/O memory. There is no protection against the stack overwriting RAM that has been reserved for variables. There is no protection against the stack overwriting itself.

Therefore, you've got to be careful to make sure of a couple of things:
1) Limit the depth of nested subroutine calls, so that the size of the stack is limited. This is a good idea in general, but it becomes more important as the size of RAM decreases.

2) Make sure that every subroutine (R)CALL has a matching RET instruction, so that the addresses which are pushed on the stack will get popped off and the stack size will be bounded.

3) For every PUSH, make sure you have a correspondng POP.

4) Every enabled interrupt source should have its interrupt vector point to a valid ISR. All possible exit points in a valid ISR should be terminated with a RETI (sometimes RET may be appropriate) instruction. (In fact, there may be exeptional cases where an ISR doesn't need to have a RET -- but these are quite rare, and you'll probably have to determine on your own if the application warrants it.)

5) Limit the possiblity of multiple ISRs being executed concurrently. If you enable interrupts while inside an ISR, then it is possible for an ISR to be interrupted. In this case, it is conceivable that you could be innundated with interrupts too frequently, such that no one ISR can ever have a chance to finish. In this case, the stack will very quickly fill up. Interrupts should be disabled in ISRs if at all possible. If that is not possible for your application, then at the very least, some other measure must be taken to ensure that the maximum number of concurrent interrupts is bounded.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your detailed reply!
You helped me to significatly improve my understanding on the AVR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lfmorrison wrote:
The stack pointer will happily decrement below 0x60. It will start modifying the I/O registers.

A quick simulation in AVR Studio seems to indicate that the SREG, SPH, and SPL registers will be unaffected by an attempt to PUSH something to their locations. However, all the other I/O locations will be treated as if they were just another location in RAM. And you'll see crazy things start happening in your AVR's peripherals.

When the stack pointer reaches 0x0000, it will wrap-around to the top of the data memory space and start writing to the top of RAM again.

There is no hardware protection against the stack writing to I/O memory. There is no protection against the stack overwriting RAM that has been reserved for variables. There is no protection against the stack overwriting itself.

Therefore, you've got to be careful to make sure of a couple of things:
1) Limit the depth of nested subroutine calls, so that the size of the stack is limited. This is a good idea in general, but it becomes more important as the size of RAM decreases.

2) Make sure that every subroutine (R)CALL has a matching RET instruction, so that the addresses which are pushed on the stack will get popped off and the stack size will be bounded.

3) For every PUSH, make sure you have a correspondng POP.

4) Every enabled interrupt source should have its interrupt vector point to a valid ISR. All possible exit points in a valid ISR should be terminated with a RETI (sometimes RET may be appropriate) instruction. (In fact, there may be exeptional cases where an ISR doesn't need to have a RET -- but these are quite rare, and you'll probably have to determine on your own if the application warrants it.)

5) Limit the possiblity of multiple ISRs being executed concurrently. If you enable interrupts while inside an ISR, then it is possible for an ISR to be interrupted. In this case, it is conceivable that you could be innundated with interrupts too frequently, such that no one ISR can ever have a chance to finish. In this case, the stack will very quickly fill up. Interrupts should be disabled in ISRs if at all possible. If that is not possible for your application, then at the very least, some other measure must be taken to ensure that the maximum number of concurrent interrupts is bounded.

Thanks for this information. I know its a very old post but I'm having issues with my program and suspected it was the amount of nested subroutines. Going to check the stack during operation to see whats happening.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 I'm having issues with my program and suspected it was the amount of nested subroutines

That is extremely unlikely, unless you forget to initialize SPH & SPL to the ram limit (I believe some newer AVRs do this automatically), or you gobble up all of your ram with variables (and hopefully not text that should be put in flash).   It can easily happen if you get unexpected recursion or have improper interrupt control.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
That is extremely unlikely, unless
your functions have large automatic (local variables) structs or arrays.  It's not difficult to do this if you aren't paying close attention.

Letting the smoke out since 1978

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
It can easily happen if you get unexpected recursion ...
A linter can detect an obviously incorrect recursion terminator.

https://rules.sonarsource.com/c/RSPEC-2190?search=stack

[6 of 7]

Recursion should not be infinite

via SonarCFamily for C | C static code analysis | SonarSource (C linter)

 

 

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Hexluthor wrote:
Going to check the stack during operation to see whats happening.
Atmel Studio 7 - Stack Overflow Detection Using Data Breakpoint

though some AVR OCD are reduced function (reduced quantity of address comparators)

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

EDIT - Deleted post, sorry - replied to wrong thread

Last Edited: Tue. Jan 28, 2020 - 02:06 PM