From 7524610b310203c423f0fd593a05baca603e3a6c Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 5 Jan 2015 02:27:24 +0100 Subject: fixes #1796 --- lib/system/gc.nim | 36 ++++++++++++++++++++++++++++++++---- tests/gc/closureleak.nim | 4 ++-- tests/gc/cyclecollector.nim | 21 +++++++++++++++++++++ tests/gc/gctest.nim | 3 ++- tests/testament/categories.nim | 13 +++++++++---- 5 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 tests/gc/cyclecollector.nim diff --git a/lib/system/gc.nim b/lib/system/gc.nim index e0db3fba4..58587cf7f 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -49,7 +49,7 @@ type waMarkGlobal, # part of the backup/debug mark&sweep waMarkPrecise, # part of the backup/debug mark&sweep waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, - waCollectWhite, + waCollectWhite #, waDebug TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} # A ref type can have a finalizer that is called before the object's @@ -595,9 +595,15 @@ proc scan(s: PCell) = else: s.setColor(rcWhite) forAllChildren(s, waScan) - + proc collectWhite(s: PCell) = - if s.color == rcWhite and s notin gch.cycleRoots: + # This is a hacky way to deal with the following problem (bug #1796) + # Consider this content in cycleRoots: + # x -> a; y -> a where 'a' is an acyclic object so not included in + # cycleRoots itself. Then 'collectWhite' used to free 'a' twice. The + # 'isAllocatedPtr' check prevents this. This also means we do not need + # to query 's notin gch.cycleRoots' at all. + if isAllocatedPtr(gch.region, s) and s.color == rcWhite: s.setColor(rcBlack) forAllChildren(s, waCollectWhite) freeCyclicCell(gch, s) @@ -648,6 +654,28 @@ when useMarkForDebug or useBackupGc: if objStart != nil: markS(gch, objStart) +when logGC: + var + cycleCheckA: array[100, PCell] + cycleCheckALen = 0 + + proc alreadySeen(c: PCell): bool = + for i in 0 ..