fixes #22664; guard against potential seqs self assignments (#22671)

fixes #22664
This commit is contained in:
ringabout
2023-09-08 23:05:57 +08:00
committed by GitHub
parent d45270bdf7
commit 5f13e15e0a
3 changed files with 38 additions and 0 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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)]"