I am using Nim self-built from git 07d7d35.
I run this program:
type Mirror = ref object
var m1 = Mirror(tag:1)
var m2 = Mirror(tag:2)
var m3 = Mirror(tag:3)
m1.other = m2; m1.other = m3
m2.other = m1; m2.other = m3
m3.other = m1; m3.other = m2
for i in 1..30000:
var mx : Mirror; mx.deepCopy(m1)
m1 = mx
This creates a data structure of three objects that all reference each other then deepcopies it over and over. On my machine this runs for 20,120 iterations, then crashes. The traceback looks like
Traceback (most recent call last)
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Error: execution of an external program failed: 'c:\msys64\home\andi\work\h\nim-practice\test3.exe '
In my tests:
Because my test in #4339 suggests that deepCopy does not alter the structure after the first iteration, and because of the GC_fullCollect thing, my guess is that this occurs when a garbage collection occurs in the middle of a deepcopy.
Expected behavior: If deepCopy on a recursive data structure is something you're not supposed to do this should be documented, but even if it's something you're not supposed to do it probably shouldn't segfault.
By the way, neither this nor #4339 are blocking me on anything. I discovered this by accident when I used deepCopy in a place I meant to use shallowCopy anyway.
DeepCopy is essential for Nim's multi threading though and NEEDS to work. :-)
@Araq So why is it that the GC needs to be disabled during deepcopies?
@Varriount Because deepCopy temporarily modifies the GC header. It uses a "forwarding" pointer to avoid a temporary hash table for the cycle detection.