a stack canary
Coal miners once carried a canary in a cage: if dangerous gas seeped in, the bird collapsed first, warning the miners before they were harmed. A stack canary is the same early-warning idea in memory: the compiler places a secret guard value just before the saved return address, and checks it right before the function returns. If a buffer overflow has marched through that value on its way to the return address, the guard will be wrong — and the program aborts before the corrupted return address is ever used.
Here is how it works step by step. When a protected function starts (its prologue), the compiler inserts code that copies a secret canary value onto the stack, positioned between the local buffers and the saved return address — exactly the path an overflow must cross. Just before the function returns (its epilogue), inserted code reloads that stack slot and compares it to the original secret; if they differ, it calls a handler that prints 'stack smashing detected' and aborts. Because a contiguous overflow that overwrites the return address MUST also overwrite the canary sitting in front of it, the mismatch is caught. The canary is typically random per run (so the attacker cannot predict it) and often includes a null byte to stop string-copy overflows from leaking or skipping past it. GCC and Clang enable this with options like -fstack-protector-strong.
It matters as a cheap, automatic, compiler-applied defense that catches the classic stack-smashing pattern before the hijack completes. The honest caveats are important: a canary only protects the SAVED RETURN ADDRESS path — it does nothing for heap overflows, use-after-free, type confusion, or overwrites of a local function pointer that sits BEFORE the canary. And it can be defeated if the attacker LEAKS the canary value (then they overwrite it with the correct value) or overwrites the return address WITHOUT crossing the canary (for example via an arbitrary write rather than a contiguous overflow). It is one layer, not a guarantee.
// what the compiler inserts (conceptually): fn() { long canary = __stack_chk_guard; // prologue: secret onto the stack char buf[16]; ... /* overflow of buf overwrites canary before the return address */ if (canary != __stack_chk_guard) // epilogue: verify before ret __stack_chk_fail(); // -> 'stack smashing detected', abort }
The canary sits in the overflow's path; a mismatch at the epilogue aborts before the return address is trusted.
A canary guards only the return-address path against a contiguous overflow; leak the canary, or write the return address directly via an arbitrary write, and it is bypassed — it does nothing for heap bugs or use-after-free.