From 19e1dc596c4bf8d0e8624539717708f7834a0d03 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 26 Oct 2020 10:13:37 +0200 Subject: [PATCH] fix #15704 #15597 wrong VM register was freed (#15705) * fix #15704 #15597 wrong VM register was freed * same treatment for nkCheckedFieldExpr * note concerning HighRegisterPressure * bump NimPatch * Update lib/system.nim Co-authored-by: Andreas Rumpf --- compiler/vmgen.nim | 6 +- tests/vm/tvmmisc.nim | 130 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 5ba15bb2bb6d2..f084ab7bad649 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -247,6 +247,8 @@ proc freeTemp(c: PCtx; r: TRegister) = proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister = # if register pressure is high, we re-use more aggressively: let c = cc.prc + # we could also customize via the following (with proper caching in ConfigRef): + # let highRegisterPressure = cc.config.getConfigVar("vm.highRegisterPressure", "40").parseInt if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister): for i in 0..c.maxSlots-n: if not c.slots[i].inUse: @@ -1508,14 +1510,14 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = let tmp = c.genx(ri) c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp) c.freeTemp(tmp) - c.freeTemp(idx) + # c.freeTemp(idx) # BUGFIX, see nkDotExpr c.freeTemp(objR) of nkDotExpr: let dest = c.genx(le[0], {gfNode}) let idx = genField(c, le[1]) let tmp = c.genx(ri) c.preventFalseAlias(le, opcWrObj, dest, idx, tmp) - c.freeTemp(idx) + # c.freeTemp(idx) # BUGFIX: idx is an immediate (field position), not a register c.freeTemp(tmp) c.freeTemp(dest) of nkDerefExpr, nkHiddenDeref: diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 61a187faf9a5e..f05bb6dece25a 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -281,3 +281,133 @@ block: # bug #8007 # OK with seq & object variants const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)] doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" + +block: # VM wrong register free causes errors in unrelated code + block: # bug #15597 + #[ + Error: unhandled exception: 'sym' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect] + in /Users/timothee/git_clone/nim/Nim_prs/compiler/vm.nim(1176) rawExecute + in opcIndCall + in let prc = if not isClosure: bb.sym else: bb[0].sym + ]# + proc bar2(head: string): string = "asdf" + proc gook(u1: int) = discard + + type PathEntry = object + kind: int + path: string + + iterator globOpt(): int = + var u1: int + + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + gook(u1) + + var entry = PathEntry() + entry.path = bar2("") + if false: + echo "here2" + + proc processAux(a: float) = discard + + template bar(iter: untyped): untyped = + var ret: float + for x in iter: break + ret + + proc main() = + processAux(bar(globOpt())) + static: main() + + block: # ditto + # D20201024T133245 + type Deque = object + proc initDeque2(initialSize: int = 4): Deque = Deque() + proc len2(a: Deque): int = 2 + proc baz(dir: string): bool = true + proc bar2(head: string): string = "asdf" + proc bar3(path: var string) = path = path + + type PathEntry = object + kind: int + path: string + + proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = dir + + iterator globOpt(dir: string): int = + var stack = initDeque2() + doAssert baz("") + let z = stack.len2 + if stack.len2 >= 0: + var entry = PathEntry() + let current = if true: stack.len2 else: stack.len2 + entry.path = bar2("") + bar3(entry.path) + if false: + echo "here2" # comment here => you get same error as https://github.com/nim-lang/Nim/issues/15704 + + proc processAux(a: float) = discard + + template bar(iter: untyped): untyped = + var ret: float + for x in iter: break + ret + proc main() = + processAux(bar(globOpt(initGlobOpt(".")))) + static: main() + + block: # bug #15704 + #[ + Error: attempt to access a nil address kind: rkFloat + ]# + type Deque = object + proc initDeque2(initialSize: int = 4): Deque = Deque() + proc len2(a: Deque): int = 2 + + proc baz(dir: string): bool = true + proc bar2(head: string): string = "asdf" + proc bar3(path: var string) = path = path + + type PathEntry = object + kind: int + path: string + depth: int + + proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = + dir + + iterator globOpt(dir: string): int = + var stack = initDeque2() + doAssert baz("") + let z = stack.len2 + var a5: int + if stack.len2 >= 0: + var entry = PathEntry() + if false: + echo "here" + let current = if true: stack.len2 else: stack.len2 + entry.depth = 1 + entry.path = bar2("") + bar3(entry.path) + proc processAux(a: float) = discard + template bar(iter: untyped): untyped = + var ret: float + for x in iter: + break + ret + const dir = "." + proc main() = + processAux(bar(globOpt(initGlobOpt(dir)))) + static: main()