I've been chasing some random crashes in a program I'm writing. I was able to reduce the problem to the small program below.
type
Vector = ref array[2, float64]
Matrix = ref array[2, Vector]
proc newVector(): Vector =
new(result)
proc newMatrix(): Matrix =
new(result)
for ix in 0 .. 1:
result[ix] = newVector()
let m = newMatrix()
m[0][0] = 1.0
echo "m[0][0] = ", m[0][0]
GC_fullCollect()
m[0][0] = 2.0
echo "m[0][0] = ", m[0][0]
This program crashes during the garbage collection with a
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
It looks like the vectors in the m matrix are being garbage collected at the first collection. This obviously creates problems.
Replacing
for ix in 0 .. 1:
result[ix] = newVector()
in newMatrix with
for v in result[].mitems:
v = newVector()
does work.
I'm not very sure what is going on. I think that the original version should work. Am I wrong in thinking that ? Or did I make a mistake ? Or is this a GC bug ?
Try:
type
Vector = ref object
value: array[2, float64]
Matrix = ref object
value: array[2, Vector]
IX = range[0..1]
proc newVector(): Vector =
new(result)
proc newMatrix(): Matrix =
new(result)
for ix in 0 .. 1:
result.value[ix] = newVector()
proc `[]=`(v: Vector, i: IX, value: float64) =
v.value[i] = value
proc `[]`(v: Vector, i: IX): float64 =
v.value[i]
proc `[]`(m: Matrix, i: IX): Vector =
m.value[i]
let m = newMatrix()
m[0][0] = 1.0
echo "m[0][0] = ", m[0][0]
GC_fullCollect()
m[0][0] = 2.0
echo "m[0][0] = ", m[0][0]
In case it helps, the exception is coming from gc.nim's forAllChildren function. The cell.typ is nil, and this line fails:
let marker = cell.typ.marker
You are only using ref and new, so it looks like a bug in GC.
It's not a bug in GC.
ref array could not allocate memory from heap. ref array is a bad represent.
Thanks everybody for all the replies.
I've got an even smaller example by now (see below). It seems to be a problem with the ref counting.
In the lines ...
result[0] = new Vector
result[1] = new Vector
... the newly created vectors do not seem have their initial ref count set to 1 (which I think it should).
type
Vector = ref array[2, float64]
Matrix = ref array[2, Vector]
proc newMatrix(): Matrix =
new(result)
result[0] = new Vector
result[1] = new Vector
var m = newMatrix()
echo "m[0] ref count :", echo m[0].getRefCount()
m[0][0] = 1.0
GC_fullCollect()
m[0][0] = 2.0
@Araq: It was a bit bussy at work, so I didn't find the time yet to post the bug on github. But I noticed it was alread fixed :-) Thanks for that.
I can confirm that the fix indeed fixes the crashes I my program. Thanks again for the very fast fix.