Whetstone
0day streak

Debugging Embedded & Systems Code

Reading a crash, the bug classes worth recognising on sight, and debugging without a search engine.

6

Questions

4/2/0

Easy / Med / Hard

Your accuracy

A live coding round often means debugging someone else's broken C with no internet access and a clock running -- which rewards recognising bug shapes on sight over reasoning from first principles every time.

A segmentation fault means the program touched memory it isn't allowed to touch -- dereferencing a null or wild pointer, reading past the end of an array into unmapped memory, writing to memory marked read-only (like a string literal). It's the OS's memory-protection hardware catching the access and killing the process before it does more damage, which makes it a relatively friendly crash: it fails loudly, immediately, near the actual bug. Memory corruption that doesn't segfault -- a small buffer overflow that lands inside memory that's still mapped -- is worse precisely because nothing stops you at the scene of the crime.

A null pointer dereference is the single most common crash in C and C++ code, and the fix discipline is almost always the same: check a pointer for null before using it, especially right after anything that can return null -- malloc under memory pressure, a failed lookup, an uninitialised pointer nobody assigned yet.

An off-by-one error is a boundary miscounted by exactly one -- looping <= instead of < against an array's length, or the reverse, is the canonical case, and it's worth checking first whenever a bug's symptom is "the last element is wrong" or "this reads one past where it should."

A memory leak doesn't crash anything immediately, which is what makes it dangerous on a long-running device -- available memory shrinks a little at a time until, eventually, an allocation fails somewhere with no obvious connection to the code that actually leaked. Tools like Valgrind exist specifically to catch this class of bug by tracking every allocation and flagging what was never freed.

A debugger like gdb lets you stop a program mid-execution, inspect memory and registers, and step instruction by instruction -- which is the practical alternative to littering code with print statements, especially useful when the bug only reproduces under specific timing. A core dump is a snapshot of a crashed process's memory taken at the moment it died, loadable into a debugger afterward -- essential when a crash isn't reliably reproducible and you only get one look at it.

Reading a stack trace backward tells you the call chain that led to the crash -- the top frame is where it actually failed, and each frame below it is "called from here," down to main. The instinct to fix the top frame is usually right, but not always: sometimes the top frame is a symptom (writing through a pointer that was already corrupted three calls earlier), and the actual bug is further down.