The following code causes segmentation fault in decRef:
type Foo* = object
case flag: bool
of true:
result: seq[int]
of false:
callback: (proc() {.closure.})
var f: Foo
f.callback = proc() = nil
f.flag = true
f.result = @[5, 10]
->
Traceback (most recent call last)
a.nim(12) a
assign.nim(132) genericSeqAssign
assign.nim(96) genericAssign
assign.nim(64) genericAssignAux
gc.nim(282) unsureAsgnRef
gc.nim(180) decRef
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
When callback is set to nil before resetting flag everything works correctly. Is this intended?
In the example the kind field is called the discriminator: For safety its address cannot be taken and assignments to it are restricted: The new value must not lead to a change of the active object branch. For an object branch switch system.reset has to be used.
But that's really unfortunate as it violates runtime safety (and I think I've seen Araq claiming that Nim code may be unsafe only if it uses addr, cast etc). Shouldn't compiler automatically call reset before transition or somehow disallow this code at compile time?
About unsafe code:
var t: string
echo t & "boom"
Shouldn't compiler automatically call reset before transition or somehow disallow this code at compile time?
Yup and there are a couple of bug reports open for this. The solution that I prefer is to prevent assignments to the discriminant altogether and make people use full assignments like obj = MyObj(flag: true, result: seq[string]).
To be honest I consider this the biggest loophole in Nim's safety, but everybody blames nil instead. ;-)