From 2e12d3e26bd39205a2aa61a8873173e579cbcb9e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 13 Jun 2023 18:03:20 +0800 Subject: [PATCH] fixes #22058; invalid free with {.noSideEffect.} in template (#22088) --- compiler/injectdestructors.nim | 39 +++++++++++++++++----------------- tests/arc/tmalloc.nim | 16 ++++++++++++++ 2 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 tests/arc/tmalloc.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 8beaa9d4f2..f684aba5ce 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -703,6 +703,24 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false, of nkWhen: # This should be a "when nimvm" node. result = copyTree(n) result[1][0] = processCall(n[1][0], s) + + of nkPragmaBlock: + var inUncheckedAssignSection = 0 + let pragmaList = n[0] + for pi in pragmaList: + if whichPragma(pi) == wCast: + case whichPragma(pi[1]) + of wUncheckedAssign: + inUncheckedAssignSection = 1 + else: + discard + result = shallowCopy(n) + inc c.inUncheckedAssignSection, inUncheckedAssignSection + for i in 0 ..< n.len-1: + result[i] = p(n[i], c, s, normal) + result[^1] = maybeVoid(n[^1], s) + dec c.inUncheckedAssignSection, inUncheckedAssignSection + else: assert(false) proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = @@ -732,7 +750,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode = if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, - nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}: + nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}: template process(child, s): untyped = p(child, c, s, mode) handleNestedTempl(n, process, tmpFlags = tmpFlags) elif mode == sinkArg: @@ -928,25 +946,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing if mode == normal: result = ensureDestruction(result, n, c, s) - of nkPragmaBlock: - var inUncheckedAssignSection = 0 - let pragmaList = n[0] - for pi in pragmaList: - if whichPragma(pi) == wCast: - case whichPragma(pi[1]) - of wUncheckedAssign: - inUncheckedAssignSection = 1 - else: - discard - result = shallowCopy(n) - inc c.inUncheckedAssignSection, inUncheckedAssignSection - for i in 0 ..< n.len: - result[i] = p(n[i], c, s, normal) - dec c.inUncheckedAssignSection, inUncheckedAssignSection - if n.typ != nil and hasDestructor(c, n.typ): - if mode == normal: - result = ensureDestruction(result, n, c, s) - of nkHiddenSubConv, nkHiddenStdConv, nkConv: # we have an "ownership invariance" for all constructors C(x). # See the comment for nkBracket construction. If the caller wants diff --git a/tests/arc/tmalloc.nim b/tests/arc/tmalloc.nim new file mode 100644 index 0000000000..1d72646c85 --- /dev/null +++ b/tests/arc/tmalloc.nim @@ -0,0 +1,16 @@ +discard """ + matrix: "--mm:arc -d:useMalloc; --mm:arc" +""" + +block: # bug #22058 + template foo(): auto = + {.noSideEffect.}: + newSeq[byte](1) + + type V = object + v: seq[byte] + + proc bar(): V = + V(v: foo()) + + doAssert bar().v == @[byte(0)]