The search term you are looking for is "Memory Protection Unit". This is available on many ARM Cortex M devices, usually the higher end parts but I think ST (and maybe others) make some Cortex M0 parts with this function. I'm not aware of any 8 bit devices with memory protection.
As brucehoult said, it's impossible to catch all "stack overflows" in general, as stack access, on most architectures, is just a normal memory operation.
Now, a commonly used approach is to set up "stack guards" - small buffers put between the stack and the heap, and then write protect those guards, either with an MPU if available, or watching for modifications in the guard buffer, initialized with sentinel values, on a regular basis, if not. This of course won't catch all issues, as Bruce explained. But it's better than nothing.
The search term you are looking for is "Memory Protection Unit". This is available on many ARM Cortex M devices, usually the higher end parts but I think ST (and maybe others) make some Cortex M0 parts with this function. I'm not aware of any 8 bit devices with memory protection.
You can't in general automatically tell whether a memory access is supposed to be to the stack or the heap, at either the machine code or the C level.
If stack accesses are only ever within N bytes of the stack pointer and the stack pointer is never adjusted by more than N bytes then you can put a protected area of N bytes between the stack and the heap.
But if a function uses an array as a local variable with either the size or an index supplied as an argument then you can't guaranteed those conditions and the stack can leap right over the protected area. That's true regardless of which order you put the stack and the heap in RAM, or even if they are in different blocks of RAM with large unmapped parts of the address space between them.
Still, a protected area will in practice catch most casual errors. It's just not guaranteed.
Recursive functions is what tends to blow up a stack to massive sizes, so avoid those.
Recursive functions is what tends to blow up a stack to massive sizes, so avoid those.
I really don't like this blind anti-recursion advice.
Recursion is an extremely valuable tool in the programmer's toolbox. You should of course understand what your algorithm is doing. Out of control iteration and out of control recursion are equally bad.
Another option is to flip the standard stack and heap layout.
so you place the stack in a defined region below the heap, and then if the stack overflows, you will get a hardfault when the stack overflows.
Recursive functions is what tends to blow up a stack to massive sizes, so avoid those.I really don't like this blind anti-recursion advice.
Recursion is an extremely valuable tool in the programmer's toolbox. You should of course understand what your algorithm is doing. Out of control iteration and out of control recursion are equally bad.
Edit: Beaten to it by dgtl
Another option is to flip the standard stack and heap layout.
so you place the stack in a defined region below the heap, and then if the stack overflows, you will get a hardfault when the stack overflows.
More information can be found here: https://github.com/knurling-rs/flip-link
You can't in general automatically tell whether a memory access is supposed to be to the stack or the heap, at either the machine code or the C level.
You can't in general automatically tell whether a memory access is supposed to be to the stack or the heap, at either the machine code or the C level.Well, you could have that 40 years ago with Intel 8086 segmentation. The 80286 added a protected mode which IIRC actually enforced that stack accesses do not overflow to code/heap, although they could still overflow to other stack variables.
Of course it was a PITA for C implementations so as soon as the 80386 offered 32 bit address space the lazy programmers bypassed the whole mechanism and emulated flat addressing.
The way I have been doing this is to fill the RAM (in the .s startup code, usually) with a value other than 0x00 - say 0xaa or 0x55, or better still fill the stack with 0xaa and the rest (DATA & BSS, where the heap ends up) with 0x55. And the RTOS memory with something yet different.
Then as you run the target, you can easily see how much of each is getting used up, over time.
Using an ISR to monitor all this is very clever
But the real challenge, in most embedded systems, is: what the hell are you going to do if it runs out of RAM? If there is an LCD, you could put up a Windows 3.1 "general protection fault at [address]"
I don't like recursion. It is not the same thing as a loop getting stuck, because under an RTOS everything else will still be running (if possibly slower) whereas if recursion bombs the stack, the whole thing blows up. Even without an RTOS, interrupts can continue running.
I had memory protection (page fault trap) in processors like the Z280, in 1987, and there were chips like the Z8000 MMU, mid-1980s or so, but never enabled it because there was nothing useful one could do in an embedded system, other than a reboot, which is not acceptable to the customer, so it had to be assured by design and testing, with defensive coding practices
Well, yes, it just doesn't do anything for a language like C or Pascal at all.
Suppose you write a function to sort an array. The function gets a pointer to the start of the array in C or a VAR parameter in Pascal (which is a pointer under the hood), and a length and then starts doing comparisons and swaps of array elements.
The function can be passed arrays that are global variables (data segment), or allocated on the heap with malloc() or new (also data segment), or that are local variables in the calling function or one of its parents in Pascal (Stack segment). It has to work with all of them. The only solution is to pass both the segment number and the offset and copy the segment number into ES to access the array.
And then when you index the array you have no idea whether you should be checking for overflowing the stack or the heap.