summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2022-03-20 14:02:44 +0100
committerGitHub <noreply@github.com>2022-03-20 14:02:44 +0100
commit731eabc9309997775c8be41f3e5eb5512460aad0 (patch)
tree6a9ee1b3695e221f591d7165097bb4b870a3f408
parent3e83d73f272afe8de85189da7d6d513916cc2efd (diff)
downloadNim-731eabc9309997775c8be41f3e5eb5512460aad0.tar.gz
fixes #19631 (#19618)
Aliasing is hard and we have to watch out not to compile 'x = f(x.a)' into 'f(x.a, addr x)'
-rw-r--r--compiler/ccgcalls.nim11
-rw-r--r--tests/ccgbugs/tcgbug.nim31
2 files changed, 39 insertions, 3 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index ce5fbfdd7..05be51a45 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -21,7 +21,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
     # we have to be *very* conservative:
     result = canRaiseConservative(n)
 
-proc preventNrvo(p: BProc; le, ri: PNode): bool =
+proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
   proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
     var n = le
     while true:
@@ -54,6 +54,11 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool =
     if canRaise(ri[0]) and
         locationEscapes(p, le, p.nestedTryStmts.len > 0):
       message(p.config, le.info, warnObservableStores, $le)
+  # bug #19613 prevent dangerous aliasing too:
+  if dest != nil and dest != le:
+    for i in 1..<ri.len:
+      let r = ri[i]
+      if isPartOf(dest, r) != arNo: return true
 
 proc hasNoInit(call: PNode): bool {.inline.} =
   result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
@@ -79,7 +84,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
     if isInvalidReturnType(p.config, typ):
       if params != nil: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
-      if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
+      if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
         # Great, we can use 'd':
         if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
         elif d.k notin {locTemp} and not hasNoInit(ri):
@@ -442,7 +447,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
     if isInvalidReturnType(p.config, typ):
       if ri.len > 1: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
-      if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
+      if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
         # Great, we can use 'd':
         if d.k == locNone:
           getTemp(p, typ[0], d, needsInit=true)
diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim
index db9c116be..0fe4b8852 100644
--- a/tests/ccgbugs/tcgbug.nim
+++ b/tests/ccgbugs/tcgbug.nim
@@ -91,3 +91,34 @@ proc test(c: Helper): string =
   c.formatted
 
 echo test(Helper(isKind: true, formatted: "ok"))
+
+
+# bug #19613
+
+type
+  Eth2Digest = object
+    data: array[42, byte]
+
+  BlockId* = object
+    root*: Eth2Digest
+
+  BlockSlotId* = object
+    bid*: BlockId
+    slot*: uint64
+
+func init*(T: type BlockSlotId, bid: BlockId, slot: uint64): T =
+  #debugecho "init ", bid, " ", slot
+  BlockSlotId(bid: bid, slot: slot)
+
+proc bug19613 =
+  var x: BlockSlotId
+  x.bid.root.data[0] = 42
+
+  x =
+    if x.slot > 0:
+      BlockSlotId.init(x.bid, x.slot)
+    else:
+      BlockSlotId.init(x.bid, x.slot)
+  doAssert x.bid.root.data[0] == 42
+
+bug19613()