diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2024-05-03 22:29:56 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-03 22:29:56 +0800 |
commit | 36bf3fa47b81e1670bb82df5cc7e22334a9dbc32 (patch) | |
tree | 939331bd21a076a4f5a338a146f3ea450bc0dbed | |
parent | d772186b2dbacdbeceaf2cd3ed3bd583f912e6e3 (diff) | |
download | Nim-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.nim | 7 | ||||
-rw-r--r-- | lib/system/seqs_v2.nim | 6 | ||||
-rw-r--r-- | tests/stdlib/ttypeinfo.nim | 17 |
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() |