Zásobník, který nikdo nedeklaruje
Statická data mají velikost, kterou spočítá linker. Halda má velikost, kterou někdo nastavil. Zásobník má velikost, kterou nikdo nezná — a přeteče do toho, co je pod ním, bez jediného varování.
Dva sčítance, druhý se zapomíná
První část je nejhlubší řetěz volání v programu. Ta druhá je to, co se na něj může navršit shora: každé přerušení si uloží kontext a zavolá obsluhu, a když je povolené vnořování, můžou se navršit všechna. Rámec obsluhy bývá větší než běžný — na Cortex-M s plovoucí čárkou má uložený kontext přes sto bajtů.
A tady je ta zákeřnost: nejhorší případ nastane, když se nejhlubší volání sejde s nejvíc vnořenými přerušeními. To se stane zřídka — takže deska funguje týdny a pak jednou spadne. Přetečení zásobníku je nejčastější příčina závady, která se nedá zopakovat.
Jak se to zjistí, když to nejde spočítat
- Vyplnit zásobník vzorkem (0xAA) při startu a po hodinách provozu se podívat, kam až se přepsal. Nejjednodušší a nejspolehlivější metoda, jakou embedded má.
- MPU jako zarážka. Nastavit oblast pod zásobníkem jako zakázanou; přetečení pak nevyrobí tichou chybu, ale výjimku s adresou.
- Statická analýza volacího grafu. Umí to překladač i nástroje; selže jen na ukazatelích na funkce a rekurzi — což jsou právě dvě věci, které do embedded kódu nepatří.
Flash má jiné pravidlo
Program se do flash vejde, nebo ne, a linker to řekne při překladu. Zajímavější je, že flash je pomalejší než jádro a čte se s čekacími stavy (kapitola 3). Kód, který se vejde do cache, běží znatelně rychleji než ten, který se z ní vypadává — a proto se rozpočet taktů z kapitoly 7 nikdy netrefí přesně z počtu instrukcí.