summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2024-05-03 22:29:56 +0800
committerGitHub <noreply@github.com>2024-05-03 22:29:56 +0800
commit36bf3fa47b81e1670bb82df5cc7e22334a9dbc32 (patch)
tree939331bd21a076a4f5a338a146f3ea450bc0dbed
parentd772186b2dbacdbeceaf2cd3ed3bd583f912e6e3 (diff)
downloadNim-36bf3fa47b81e1670bb82df5cc7e22334a9dbc32.tar.gz
fixes #23556; typeinfo.extendSeq generates random values in ORC (#23557)
fixes #23556

It should somehow handle default fields in the future
-rw-r--r--lib/core/typeinfo.nim7
-rw-r--r--lib/system/seqs_v2.nim6
-rw-r--r--tests/stdlib/ttypeinfo.nim17
3 files changed, 28 insertions, 2 deletions
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index 5075c8458..3c5433836 100644
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -129,7 +129,9 @@ when not defined(gcDestructors):
 else:
   proc nimNewObj(size, align: int): pointer {.importCompilerProc.}
   proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.importCompilerProc.}
-  proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
+  proc prepareSeqAddUninit(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
+    importCompilerProc.}
+  proc zeroNewElements(len: int; p: pointer; addlen, elemSize, elemAlign: int) {.
     importCompilerProc.}
 
 template `+!!`(a, b): untyped = cast[pointer](cast[int](a) + b)
@@ -221,7 +223,8 @@ proc extendSeq*(x: Any) =
     var s = cast[ptr NimSeqV2Reimpl](x.value)
     let elem = x.rawType.base
     if s.p == nil or s.p.cap < s.len+1:
-      s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAdd(s.len, s.p, 1, elem.size, elem.align))
+      s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAddUninit(s.len, s.p, 1, elem.size, elem.align))
+    zeroNewElements(s.len, s.p, 1, elem.size, elem.align)
     inc s.len
   else:
     var y = cast[ptr PGenSeq](x.value)[]
diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim
index 8b3e9ee88..572e77408 100644
--- a/lib/system/seqs_v2.nim
+++ b/lib/system/seqs_v2.nim
@@ -90,6 +90,12 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin
       q.cap = newCap
       result = q
 
+proc zeroNewElements(len: int; q: pointer; addlen, elemSize, elemAlign: int) {.
+    noSideEffect, tags: [], raises: [], compilerRtl.} =
+  {.noSideEffect.}:
+    let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign)
+    zeroMem(q +! headerSize +! len * elemSize, addlen * elemSize)
+
 proc prepareSeqAddUninit(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
     noSideEffect, tags: [], raises: [], compilerRtl.} =
   {.noSideEffect.}:
diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim
index 8d5061124..9bbc2e92c 100644
--- a/tests/stdlib/ttypeinfo.nim
+++ b/tests/stdlib/ttypeinfo.nim
@@ -74,3 +74,20 @@ block:
 
   doAssert getEnumOrdinal(y, "Hello") == 0
   doAssert getEnumOrdinal(y, "hello") == 1
+
+block: # bug #23556
+  proc test =
+    var
+      t: seq[int]
+      aseq = toAny(t)
+
+    invokeNewSeq(aseq, 0)
+
+    # Got random value only when loop 8 times.
+    for i in 1 .. 8:
+      extendSeq(aseq)
+
+    doAssert t == @[0, 0, 0, 0, 0, 0, 0, 0]
+
+  for i in 1 .. 7:
+    test()