Skip to content

Commit

Permalink
fixes #22664; guard against potential seqs self assignments (#22671)
Browse files Browse the repository at this point in the history
fixes #22664
  • Loading branch information
ringabout authored Sep 8, 2023
1 parent d45270b commit 5f13e15
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 0 deletions.
11 changes: 11 additions & 0 deletions compiler/liftdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -553,17 +553,28 @@ 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:
body.add setLenSeqCall(c, t, x, y)
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:
Expand Down
6 changes: 6 additions & 0 deletions lib/system/seqs_v2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 '*'
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions tests/arc/tarcmisc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)]"

0 comments on commit 5f13e15

Please sign in to comment.