The last couple weeks have been a bit brutal as I’ve been deeply entrenched in a particularly difficult project to debug. In the end, throwing more hours at it wasn’t as effective as I would have been had I actually stepped back and reminded myself of the basic things I know I should be doing but sometimes forget when I’m writing large swaths of embedded, kernel or OS code. This list is as much a reminder for myself as anyone else who happens to read this.
- Never assume a variable on the stack is initialized unless you did it yourself
- Always build with -Wall and fix even the most mundane of warnings before diving into debugging serious issues
- If you have to make a temporary change or hack always throw in a // XXX and a WIP checkpoint commit into git
- Make sure the code is valgrind clean at every stage of the process
- ulimit -c unlimited. Having core dumps for difficult to reproduce races makes a night and day difference
- export MALLOC_CHECK_=2. Catch the memory errors before they’re entrenched
- Use memory guards around important structures so you can watch them if needed
- Verify in the disassembly or symbol dump that what you think you compiled was actually compiled
- Verify that you’re using the proper byte order
- Double check the byte order because when it matters it really matters
- Don’t merely skim the datasheet. Don’t overlook timing tables. Know the details and be able to explain them to anyone who asks
- Don’t assume, verify
- Don’t let yourself waste time to errors a compiler could have caught