mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-02 21:49:02 +00:00
fixes #25992; fix GC tracing of stale bytes in case objects during reset
This commit is contained in:
@@ -75,6 +75,23 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
cSizeof(getTypeDesc(p.module, typ)))
|
||||
else:
|
||||
specializeResetN(p, accessor, typ.n, typ)
|
||||
if isCaseObj(typ.n):
|
||||
# The active branch was released above. Clear the complete object so
|
||||
# stale bytes from overlapping branches cannot be traced by the GC.
|
||||
# type
|
||||
# Foo = object
|
||||
# case kind: bool
|
||||
# of true:
|
||||
# a: ref Bar # 8 bytes (pointer)
|
||||
# of false:
|
||||
# b: int # 4 bytes
|
||||
# specializeResetT for b emits accessor.b = 0 — writes 4 bytes
|
||||
# But the union is 8 bytes wide (sized by the largest branch)
|
||||
# The remaining 4 bytes where a used to live are untouched
|
||||
# Those stale bytes could contain a heap pointer the GC traces → crash
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimZeroMem"),
|
||||
cCast(CPointer, cAddr(accessor)),
|
||||
cSizeof(getTypeDesc(p.module, typ)))
|
||||
of tyTuple:
|
||||
let typ = getUniqueType(typ)
|
||||
for i, a in typ.ikids:
|
||||
|
||||
56
tests/gc/tmove_case_object.nim
Normal file
56
tests/gc/tmove_case_object.nim
Normal file
@@ -0,0 +1,56 @@
|
||||
discard """
|
||||
matrix: "--mm:refc; --mm:orc"
|
||||
"""
|
||||
|
||||
type
|
||||
A = object of RootObj
|
||||
|
||||
V = object
|
||||
case g: bool
|
||||
of true:
|
||||
v: A
|
||||
of false:
|
||||
e: string
|
||||
|
||||
var r = V(g: true, v: A())
|
||||
discard move r
|
||||
GC_fullCollect()
|
||||
|
||||
type
|
||||
Kind = enum nested, other
|
||||
Nested = object
|
||||
case kind: Kind
|
||||
of nested:
|
||||
case enabled: bool
|
||||
of true: payload: A
|
||||
of false: message: string
|
||||
of other:
|
||||
discard
|
||||
|
||||
var n = Nested(kind: nested, enabled: true, payload: A())
|
||||
discard move n
|
||||
GC_fullCollect()
|
||||
|
||||
# Moving from the other branch must keep its value alive and leave the source
|
||||
# in the default state.
|
||||
var s = V(g: false, e: "hello")
|
||||
let moved = move s
|
||||
doAssert moved.e == "hello"
|
||||
doAssert not s.g
|
||||
doAssert s.e.len == 0
|
||||
|
||||
# Reinitializing the zeroed value must also restore embedded object type
|
||||
# headers.
|
||||
type W = object
|
||||
a: A
|
||||
value: V
|
||||
text: string
|
||||
|
||||
var w = W(a: A(), value: V(g: true, v: A()), text: "content")
|
||||
let movedW = move w
|
||||
doAssert movedW.text == "content"
|
||||
doAssert cast[ptr pointer](addr w.a)[] != nil
|
||||
doAssert not w.value.g
|
||||
doAssert w.value.e.len == 0
|
||||
doAssert w.text.len == 0
|
||||
GC_fullCollect()
|
||||
Reference in New Issue
Block a user