Hello,
I'm using a Cortex M-4 processor (STM32F4) and I recently encountered strange behavior of my code after minor modifications that were not directly related to the problems I was seeing.
After a bit of digging, I noticed that some of my global variables were modified without being accessed through the code. Looking at the memory mapping, it turned out these variables were located just before the stack. Increasing the stack size in the startup file solved the issue, so obviously this was a stack overflow.
But the thing is, I want to be sure that when a stack overflow occurs, a fault happens, not some random behavior. I thought I was safe because my stack was at the end of the RAM space. But as it turns out, it actually grows backwards.
So the question is: How to configure the stack direction ? And are there other ways to prevent this kind of problem?
Thank you
I don't think any of the ABI or libraries really handle going upward well.
Put the stack at the bottom of RAM, ie 0x20000000..0x20000800 so it descends into memory that will trap, ie 0x1FFFFFFF, or use CCM RAM at 0x10000000 where I expect 0x0FFFFFFF accesses to trap
"I thought I was safe because my stack was at the end of the RAM space. But as it turns out, it actually grows backwards."
Yes - that is normal and, as already noted, I don't think there's any way to change the direction it grows.
But something doesn't make sense here:
1. The stack is placed at the "end" (top) of RAM, and grows backwards.
2. Your program variables start at the "bottom" of RAM, and grow upwards.
So, if your stack was colliding with your program variables, you had filled-up all the available RAM anyhow - so increasing the Stack size would not have helped!
So, my available RAM space is 0x20000000 -> 0x20003000.
According to the .map file, my global/static variables (.data, .bss) are stored between 0x20000000 and 0x20001cd0. The stack starts right after.
I had configured its size used to 0x400, so it used the space 0x20001cd0 -> 0x200020d0.
I guess it would be better if it was something like 0x20002c00 -> 0x20003000 but I don't know how to do that. But even without this, I still don't understand how it could corrupt the last .bss segment.
Using the debugger, it was clear that after setting the stack size to 0x0600, the "beginning" of the stack (0x20001cd0 to more or less 0x20001e50) stayed unused, and it was the "end" that was used.
What do you think ? Should I be posting on the ST forums instead of here ?
A better idea would be to post a summary in the ST forum, with a link to this tread - then you don't get two unrelated threads on the same topic.
And, of course, post a link here to the ST thread.
"I still don't understand how it could corrupt the last .bss segment"
It could be that changing the stack size was just a red herring ...
Are you using Heap (dynamic allocation) ?
"But something doesn't make sense here: 1. The stack is placed at the "end" (top) of RAM, and grows backwards. 2. Your program variables start at the "bottom" of RAM, and grow upwards. So, if your stack was colliding with your program variables, you had filled-up all the available RAM anyhow - so increasing the Stack size would not have helped!"
I was a bit confused about the meaning of "up" and "down", though I gave the exact addresses in my second message. Now it is clearer to me.
So here is the initial (standard) configuration : - The program variables (.data, .bss) are stored at the bottom of RAM (0x20000000). The size they occupy is determined at compilation. - The stack memory section is located just above the variables. Its size is configurable (in the startup file), by default it is 1 kbyte. - The remaining top part of the RAM is unused
This means, at runtime, the stack starts at variables_size + stack_size, grows downwards, and when full quietly overwrites the last variables.
To ensure maximum RAM usage, one could set the stack memory section start to RAM_start + RAM_size - stack_size, which is the situation you describe (variables at the bottom, stack at the top, unused space between). This way the stack size doesn't actually matter and you only encouter a problem when all RAM is effectively used. But if it does occur, it will still be quietly, without causing an hard fault. So I guess it's not recommended.
What I want to do (but first I didn't know how to phrase it) is to put the stack at the bottom, and the variables above. This way way the stack starts at 0x20000000 + stack_size, grows downwards, and when it overflows, it tries to access an address in 0x1FFFF...., triggering a hard fault.
Alternatively, putting guard words just below the stack and checking them periodically would do the trick.
From what I gathered, it seems like I could either create a scatter file, or modify the startup file.