Hunting crashes: The ultimate guide - nim-lang/Nim GitHub Wiki
Ok, so your nice Nim program crashes under various hard-to-reproduce conditions. What can you do about that?
Generally speaking the most important question when you have a corruption is what piece of code wrote to this memory location. This question is answered by watchpoints, breakpoints are mostly useless for this. In general I found breakpoints only useful to set watchpoints in them.
Use --debugger:native
and use GDB or LLDB or Visual Studio for debugging. Note that currently local variables are mangled and a 0
is attached to the name.
--gc:boehm
--gc:refc
--gc:markAndSweep
Note that if your program does not crash with a different GC, it doesn't imply you found a GC bug! It's just a weak indicator.
- Linux
- MacOS X
- Windows
- i386 (32bit)
- amd64 (64bit)
- arm
-d:release
vs debug mode is the obvious choice, but the Nim GC, allocator and standard library have many more checks you can should enable:
-d:useSysAssert
- enables assertions in the system.nim, especially in Nim's allocator.
-d:useGcAssert
- enables assertions in Nim's GC.
-d:nimBurnFree
- overwrite deallocated memory with 0xff bytes so that "access after free" triggers a segfault.
--tlsEmulation:on|off`
- turn "thread local storage emulation on/off". This is helpful when you do have an issue in a threaded program. As I recently learned, the fact that TLS is cleaned at thread exit is often an overlooked cause for crashes. TLS is unsafer than global storage in this respect.
Even more debugging options can be enabled by editing lib/system/mmdisp.nim
. Most of these have no --define
equivalent, unfortunately.
One problem with corruptions is their non-deterministic nature, in particular heap and stack addresses change from run to run. Define -d:corruption
to enable "cell IDs", so that every "cell" (that is every ref
/string
/seq
) gets a unique ID. It's often interesting to see if the corrupted cell has the same ID from run to run or if it differs. If it differs the bug is non-deterministic. Within the GC writeCell
can be used to output offending cells.