I'm working on a project (early days) which crashes with a SIGSEGV in tests. It's pure Nim (no calls into C or anything like that) and it crashes at a point where that bit of code has been executed dozens of times. It's basically a tokenizer, and hits the error after tokenizing several dozen lines of text:
$ nimble test
Verifying dependencies for [email protected]
Compiling /home/vinay/projects/nim-cfg-lib/tests/test1 (from package config) using c backend
[OK] location
Traceback (most recent call last)
/home/vinay/projects/nim-cfg-lib/tests/test1.nim(29) test1
/home/vinay/projects/nim-cfg-lib/src/config.nim(271) getToken
/home/vinay/projects/nim-cfg-lib/src/config.nim(115) copy
/home/vinay/projects/nim-cfg-lib/src/config.nim(113) newLocation
/disk2/vinay/nim-1.6.0/lib/system/gc.nim(486) newObj
/disk2/vinay/nim-1.6.0/lib/system/gc.nim(248) decRef
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Segmentation fault (core dumped)
Error: execution of an external program failed: '/home/vinay/projects/nim-cfg-lib/tests/test1 '
Tip: 2 messages have been suppressed, use --verbose to show them.
Error: Execution failed with exit code 1
... Command: /home/vinay/nim/bin/nim c --noNimblePath -d:NimblePkgVersion=0.1.0 --hints:off -r --path:. /home/vinay/projects/nim-cfg-lib/tests/test1
So getToken() has been called without any error dozens of times, and then suddenly fails. The failing line in getToken() is near the start - the last line in this snippet:
proc getToken(self: Tokenizer) : Token =
result = newToken(Error, "")
var startLocation = self.location.copy
var endLocation = startLocation.copy
The Location code is pretty simple:
Location* = ref object of RootObj
line* : int
column* : int
proc newLocation(line: int = 1, column: int = 1) : Location = Location(line: line, column: column)
proc copy(source: Location) : Location = newLocation(source.line, source.column)
proc update(self: Location, source: Location) =
self.line = source.line
self.column = source.column
proc nextLine* (loc: Location) =
loc.line += 1
loc.column = 1
proc `$` (loc: Location) : string = &"({loc.line}, {loc.column})"
Can anyone suggest what might be wrong, and/or how to debug this kind of issue? I couldn't make a smaller standalone example which demonstrates the issue, unfortunately.Tried with all of the --gc: options other than --gc:go. Same results :-(
Fails also with --gc:none, except that I get lots of uses GC'ed memory [GcMem] messages from e.g. unittest. A SIGSEGV in all cases.
Does your code contain use of ptr, cast or addr()?
Try compile on linux with --gc:arc -d:useMalloc and run with valgrind.
Does your code contain use of ptr, cast or addr()?
https://github.com/vsajip/nim-cfg-lib/blob/main/src/config.nim#L81
TokenValue {.union.} = object
I think union pragma can be dangerous too. Can you not use Nim's object variants instead?