Skip to content

Commit b5ee81f

Browse files
authored
fix #18977; disallow change branch of an object variant in ORC (#21526)
* fix #18977 disallow change branch of an object variant in ORC * check errors for goto exception * fixes conditions * fixes tests * add a test case for #18977
1 parent 6552a27 commit b5ee81f

File tree

6 files changed

+97
-32
lines changed

6 files changed

+97
-32
lines changed

compiler/ccgstmts.nim

+3-1
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,8 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
15791579
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
15801580
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
15811581
lit])
1582+
if p.config.exc == excGoto:
1583+
raiseExit(p)
15821584

15831585
when false:
15841586
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
@@ -1603,7 +1605,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
16031605
initLocExpr(p, e[0], a)
16041606
getTemp(p, a.t, tmp)
16051607
expr(p, e[1], tmp)
1606-
if optTinyRtti notin p.config.globalOptions and p.inUncheckedAssignSection == 0:
1608+
if p.inUncheckedAssignSection == 0:
16071609
let field = dotExpr[1].sym
16081610
genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
16091611
message(p.config, e.info, warnCaseTransition)

compiler/injectdestructors.nim

+33-12
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ import
1717
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
1818
strutils, options, lowerings, tables, modulegraphs,
1919
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
20-
varpartitions, aliasanalysis, dfa
20+
varpartitions, aliasanalysis, dfa, wordrecg
2121

2222
when defined(nimPreviewSlimSystem):
2323
import std/assertions
2424

25-
from trees import exprStructuralEquivalent, getRoot
25+
from trees import exprStructuralEquivalent, getRoot, whichPragma
2626

2727
type
2828
Con = object
@@ -35,6 +35,7 @@ type
3535
idgen: IdGenerator
3636
body: PNode
3737
otherUsage: TLineInfo
38+
inUncheckedAssignSection: int
3839

3940
Scope = object # we do scope-based memory management.
4041
# a scope is comparable to an nkStmtListExpr like
@@ -342,15 +343,16 @@ It is best to factor out piece of object that needs custom destructor into separ
342343
return
343344

344345
# generate: if le != tmp: `=destroy`(le)
345-
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
346-
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
347-
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
348-
cond.add le
349-
cond.add tmp
350-
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
351-
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
352-
notExpr.add cond
353-
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
346+
if c.inUncheckedAssignSection != 0:
347+
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
348+
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
349+
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
350+
cond.add le
351+
cond.add tmp
352+
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
353+
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
354+
notExpr.add cond
355+
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
354356
result.add newTree(nkFastAsgn, le, tmp)
355357

356358
proc genWasMoved(c: var Con, n: PNode): PNode =
@@ -877,14 +879,33 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
877879
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
878880
result = n
879881

880-
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
882+
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange:
881883
result = shallowCopy(n)
882884
for i in 0 ..< n.len:
883885
result[i] = p(n[i], c, s, normal)
884886
if n.typ != nil and hasDestructor(c, n.typ):
885887
if mode == normal:
886888
result = ensureDestruction(result, n, c, s)
887889

890+
of nkPragmaBlock:
891+
var inUncheckedAssignSection = 0
892+
let pragmaList = n[0]
893+
for pi in pragmaList:
894+
if whichPragma(pi) == wCast:
895+
case whichPragma(pi[1])
896+
of wUncheckedAssign:
897+
inUncheckedAssignSection = 1
898+
else:
899+
discard
900+
result = shallowCopy(n)
901+
inc c.inUncheckedAssignSection, inUncheckedAssignSection
902+
for i in 0 ..< n.len:
903+
result[i] = p(n[i], c, s, normal)
904+
dec c.inUncheckedAssignSection, inUncheckedAssignSection
905+
if n.typ != nil and hasDestructor(c, n.typ):
906+
if mode == normal:
907+
result = ensureDestruction(result, n, c, s)
908+
888909
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
889910
# we have an "ownership invariance" for all constructors C(x).
890911
# See the comment for nkBracket construction. If the caller wants

tests/arc/t18977.nim

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
discard """
2+
matrix: "--mm:arc"
3+
"""
4+
5+
type
6+
E = enum
7+
a, b, c, d
8+
X = object
9+
v: int
10+
O = object
11+
case kind: E
12+
of a:
13+
a: int
14+
of {b, c}:
15+
b: float
16+
else:
17+
d: X
18+
19+
proc `=destroy`(x: var X) =
20+
echo "x destroyed"
21+
22+
var o = O(kind: d, d: X(v: 12345))
23+
doAssert o.d.v == 12345
24+
25+
doAssertRaises(FieldDefect):
26+
o.kind = a

tests/arc/tcaseobj.nim

+18-10
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ proc `=destroy`(o: var TMyObj) =
6060
o.p = nil
6161
echo "myobj destroyed"
6262

63-
proc `=`(dst: var TMyObj, src: TMyObj) =
63+
proc `=copy`(dst: var TMyObj, src: TMyObj) =
6464
`=destroy`(dst)
6565
dst.p = alloc(src.len)
6666
dst.len = src.len
@@ -170,18 +170,24 @@ proc test_myobject =
170170
x.x1 = "x1"
171171
x.x2 = "x2"
172172
x.y1 = "ljhkjhkjh"
173-
x.kind1 = true
173+
{.cast(uncheckedAssign).}:
174+
x.kind1 = true
174175
x.y2 = @["1", "2"]
175-
x.kind2 = true
176+
{.cast(uncheckedAssign).}:
177+
x.kind2 = true
176178
x.z1 = "yes"
177-
x.kind2 = false
179+
{.cast(uncheckedAssign).}:
180+
x.kind2 = false
178181
x.z2 = @["1", "2"]
179-
x.kind2 = true
182+
{.cast(uncheckedAssign).}:
183+
x.kind2 = true
180184
x.z1 = "yes"
181185
x.kind2 = true # should be no effect
182186
doAssert(x.z1 == "yes")
183-
x.kind2 = false
184-
x.kind1 = x.kind2 # support self assignment with effect
187+
{.cast(uncheckedAssign).}:
188+
x.kind2 = false
189+
{.cast(uncheckedAssign).}:
190+
x.kind1 = x.kind2 # support self assignment with effect
185191

186192
try:
187193
x.kind1 = x.flag # flag is not accesible
@@ -207,8 +213,9 @@ type
207213
error*: string
208214

209215
proc init(): RocksDBResult[string] =
210-
result.ok = true
211-
result.value = "ok"
216+
{.cast(uncheckedAssign).}:
217+
result.ok = true
218+
result.value = "ok"
212219

213220
echo init()
214221

@@ -222,7 +229,8 @@ type MyObj = object
222229
of true: x1: string
223230

224231
var a = MyObj(kind: false, x0: 1234)
225-
a.kind = true
232+
{.cast(uncheckedAssign).}:
233+
a.kind = true
226234
doAssert(a.x1 == "")
227235

228236
block:

tests/arc/tcaseobjcopy.nim

+15-8
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,23 @@ proc test_myobject =
169169
x.x1 = "x1"
170170
x.x2 = "x2"
171171
x.y1 = "ljhkjhkjh"
172-
x.kind1 = true
172+
{.cast(uncheckedAssign).}:
173+
x.kind1 = true
173174
x.y2 = @["1", "2"]
174-
x.kind2 = true
175+
{.cast(uncheckedAssign).}:
176+
x.kind2 = true
175177
x.z1 = "yes"
176-
x.kind2 = false
178+
{.cast(uncheckedAssign).}:
179+
x.kind2 = false
177180
x.z2 = @["1", "2"]
178-
x.kind2 = true
181+
{.cast(uncheckedAssign).}:
182+
x.kind2 = true
179183
x.z1 = "yes"
180184
x.kind2 = true # should be no effect
181185
doAssert(x.z1 == "yes")
182-
x.kind2 = false
183-
x.kind1 = x.kind2 # support self assignment with effect
186+
{.cast(uncheckedAssign).}:
187+
x.kind2 = false
188+
x.kind1 = x.kind2 # support self assignment with effect
184189

185190
try:
186191
x.kind1 = x.flag # flag is not accesible
@@ -206,7 +211,8 @@ type
206211
error*: string
207212

208213
proc init(): RocksDBResult[string] =
209-
result.ok = true
214+
{.cast(uncheckedAssign).}:
215+
result.ok = true
210216
result.value = "ok"
211217

212218
echo init()
@@ -221,7 +227,8 @@ type MyObj = object
221227
of true: x1: string
222228

223229
var a = MyObj(kind: false, x0: 1234)
224-
a.kind = true
230+
{.cast(uncheckedAssign).}:
231+
a.kind = true
225232
doAssert(a.x1 == "")
226233

227234
block:

tests/destructor/tgotoexceptions7.nim

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ proc helper = doAssert(false)
2525

2626
proc main(i: int) =
2727
var obj = Obj(kind: kindA, s: "abc")
28-
obj.kind = kindB
28+
{.cast(uncheckedAssign).}:
29+
obj.kind = kindB
2930
obj.i = 2
3031
try:
3132
var objA = ObjA()

0 commit comments

Comments
 (0)