From 4c0cd148b56fd475d98193ae601d898269870adb Mon Sep 17 00:00:00 2001 From: zerbina <100542850+zerbina@users.noreply.github.com> Date: Sat, 4 Nov 2023 20:31:08 +0100 Subject: [PATCH] fix(js): wrong code for uninitialized `pointer` locals (#1011) ## Summary Fix wrong code being generated for uninitialized locals of `pointer` type, which resulted in run-time crashes or other unexpected behaviour. ## Details * the set used in deciding whether to use a boxed pointer missed `tyPointer`. Since testing the set after the inclusion of `tyPointer` would be redundant with the `mapType` check, testing the set is simply removed * the `not isIndirect` check is replaced with testing whether a boxed pointer is used. While a loc using an indirection implies a boxed representation, the extra indirection made the logic harder to understand --- compiler/backend/jsgen.nim | 14 +++++--------- tests/js/tdefault_init_pointer_var.nim | 13 +++++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 tests/js/tdefault_init_pointer_var.nim diff --git a/compiler/backend/jsgen.nim b/compiler/backend/jsgen.nim index 1d5375dcfc..90000480e9 100644 --- a/compiler/backend/jsgen.nim +++ b/compiler/backend/jsgen.nim @@ -1673,13 +1673,12 @@ proc genVarInit(p: PProc, typ: PType, varName: string, storage: StorageFlags, s: Rope if n.kind == cnkEmpty: - let isIndirect = stfIndirect in storage - if not isIndirect and - typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(typ) == etyBaseIndex: + if mapType(typ) == etyBaseIndex and (stfBoxed notin storage): lineF(p, "var $1 = null;$n", [varName]) lineF(p, "var $1_Idx = 0;$n", [varName]) else: - lineF(p, "var $1 = $2;$n", [varName, createVar(p, typ, isIndirect)]) + let val = createVar(p, typ, stfIndirect in storage) + lineF(p, "var $1 = $2;$n", [varName, val]) else: gen(p, n, a) case mapType(typ) @@ -2293,10 +2292,7 @@ proc finishProc*(p: PProc): string = let loc {.cursor.} = p.locals[resultId] mname = loc.name - let returnAddress = not isIndirect(loc) and - loc.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and - mapType(loc.typ) == etyBaseIndex - if returnAddress: + if mapType(loc.typ) == etyBaseIndex and (stfBoxed notin loc.storage): resultAsgn = p.indentLine(("var $# = null;$n") % [mname]) resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname]) else: @@ -2304,7 +2300,7 @@ proc finishProc*(p: PProc): string = resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar]) var a: TCompRes accessLoc(mname, loc, a) - if returnAddress: + if a.typ == etyBaseIndex: returnStmt = "return [$#, $#];$n" % [a.address, a.res] else: returnStmt = "return $#;$n" % [a.res] diff --git a/tests/js/tdefault_init_pointer_var.nim b/tests/js/tdefault_init_pointer_var.nim new file mode 100644 index 0000000000..743cef212a --- /dev/null +++ b/tests/js/tdefault_init_pointer_var.nim @@ -0,0 +1,13 @@ +discard """ + description: ''' + Regression test for wrong code being generated for locals of `pointer` + type + ''' +""" + +proc test(): pointer = + # the result variable was affected too + var x: pointer + doAssert x == nil # this assertion failed + +doAssert test() == nil # this one too \ No newline at end of file