From 5f13e15e0a6f90c462a71cd30addc677f688c4dc Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 8 Sep 2023 23:05:57 +0800 Subject: [PATCH] fixes #22664; guard against potential seqs self assignments (#22671) fixes #22664 --- compiler/liftdestructors.nim | 11 +++++++++++ lib/system/seqs_v2.nim | 6 ++++++ tests/arc/tarcmisc.nim | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 387a22555ef7..a73df046ef8d 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -553,6 +553,14 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) = else: body.sons.setLen counterIdx +proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) = + var cond = callCodegenProc(c.g, "sameSeqPayload", c.info, + newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), + newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y) + ) + cond.typ = getSysType(c.g, c.info, tyBool) + body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info))) + proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind of attachedDup: @@ -560,10 +568,13 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = forallElements(c, t, body, x, y) of attachedAsgn, attachedDeepCopy: # we generate: + # if x.p == y.p: + # return # setLen(dest, y.len) # var i = 0 # while i < y.len: dest[i] = y[i]; inc(i) # This is usually more efficient than a destroy/create pair. + checkSelfAssignment(c, t, body, x, y) body.add setLenSeqCall(c, t, x, y) forallElements(c, t, body, x, y) of attachedSink: diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 3a49142bf4bb..b71b8176252a 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -32,6 +32,10 @@ type len: int p: ptr NimSeqPayload[T] + NimRawSeq = object + len: int + p: pointer + const nimSeqVersion {.core.} = 2 # XXX make code memory safe for overflows in '*' @@ -139,6 +143,8 @@ proc newSeq[T](s: var seq[T], len: Natural) = shrink(s, 0) setLen(s, len) +proc sameSeqPayload(x: pointer, y: pointer): bool {.compilerproc, inline.} = + result = cast[ptr NimRawSeq](x)[].p == cast[ptr NimRawSeq](y)[].p template capacityImpl(sek: NimSeqV2): int = if sek.p != nil: (sek.p.cap and not strlitFlag) else: 0 diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 1404f54a1bda..525c8c3a64d7 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -614,3 +614,24 @@ method process*(self: App): Option[Event] {.base.} = type Test2 = ref object of RootObj method bug(t: Test2): seq[float] {.base.} = discard + +block: # bug #22664 + type + ElementKind = enum String, Number + Element = object + case kind: ElementKind + of String: + str: string + of Number: + num: float + Calc = ref object + stack: seq[Element] + + var calc = new Calc + + calc.stack.add Element(kind: Number, num: 200.0) + doAssert $calc.stack == "@[(kind: Number, num: 200.0)]" + let calc2 = calc + calc2.stack = calc.stack # This nulls out the object in the stack + doAssert $calc.stack == "@[(kind: Number, num: 200.0)]" + doAssert $calc2.stack == "@[(kind: Number, num: 200.0)]"