I have recently been working on what I believe is a buffer overrun problem in a microcontroller with software that I wrote. I'm using an Atmega328PB, so it has no such thing as a MMU or address space isolation.
Every once in a while, some bug is causing many of my in memory values to get overwritten with a bunch of garbage. I have enabled the watchdog timer and it seems that what usually happens is a total crash of the microcontroller and the watchdog takes over.
However, what seems to have happened sometimes is it overwrites a bunch of memory values and then happens to set the flag byte I have internally for "write this to the eeprom". The microcontroller keeps running happily with these "new" configuration values. Even a power cycle won't allow this to be fixed, since the "new" values are read from EEPROM.
Is there some way I can protect my microcontroller against accidental buffer overrun and underruns? I have had a few ideas such as
- Add a sentinel byte that should always be some number. Check this all over the place and if the number is wrong, just go into an infinite loop. The watchdog resets eventually.
- Store a checksum of everything that is kept in global memory. There is practically no way random memory corruption would update the checksum to be correct. This has severe performance implications as every write to a global implies updating this checksum. The checksum needs to be validated periodically
- Store each value with its own checksum. Each read needs to validate the checksum.
Option 1 is simple but likely not to actually work for all cases. Options 2 & 3 are likely to work but have severe performance & memory implications I think.
Is there an industry standard way to protect a microcontroller from memory corruption in the absence of an MMU?
None of this has anything to do with dynamic allocation or null terminated arrays. All the C-strings I use are stored in the program memory, thus corruption of them would involve and extremely unlikely set of circumstances. Almost every single variable is at a static scope or is globally shared across the program. I don't use the dynamic heap at all. I can't prove that stack corruption is occurring, but I know that my global values are being corrupted.