diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2d4a46412c..fdd8553a3e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2198,6 +2198,13 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: putIntoDest(p, d, e, cIntValue(lengthOrd(p.config, typ))) else: internalError(p.config, e.info, "genArrayLen()") +proc isTrivialTypesToSnippet(t: PType): Snippet = + if containsGarbageCollectedRef(t) or + hasDestructor(t): + result = NimFalse + else: + result = NimTrue + proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = if optSeqDestructors in p.config.globalOptions: e[1] = makeAddr(e[1], p.module.idgen) @@ -2220,7 +2227,8 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = pExpr = cIfExpr(ra, cAddr(derefField(ra, "Sup")), NimNil) else: pExpr = ra - call.snippet = cCast(rt, cgCall(p, "setLengthSeqV2", pExpr, rti, rb)) + call.snippet = cCast(rt, cgCall(p, "setLengthSeqV2", pExpr, rti, rb, + isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0]))) genAssignment(p, a, call, {}) gcUsage(p.config, e) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 8cefe7601f..b864da8531 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -300,7 +300,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize) result.len = newLen -proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. +proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {. compilerRtl.} = sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq" if s == nil: @@ -334,7 +334,8 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. # presence of user defined destructors, the user will expect the cell to be # "destroyed" thus creating the same problem. We can destroy the cell in the # finalizer of the sequence, but this makes destruction non-deterministic. - zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize) + if not isTrivial: # optimization for trivial types + zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize) else: result = s zeroMem(dataPointer(result, elemAlign, elemSize, result.len), (newLen-%result.len) *% elemSize) diff --git a/tests/stdlib/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim index 86dcf41629..4f7707d976 100644 --- a/tests/stdlib/tmisc_issues.nim +++ b/tests/stdlib/tmisc_issues.nim @@ -37,3 +37,30 @@ block: # bug #16771 a.foo b doAssert a.n == 42 doAssert b.n == 1 + +block: # bug #24683 + block: + var v = newSeq[int](100) + v[99]= 444 + v.setLen(5) + v.setLen(100) + doAssert v[99] == 0 + + when not defined(js): + block: + var + x = @[1, 2, 3, 4, 45, 56, 67, 999, 88, 777] + + x.setLen(0) # zero-fills 1mb of released data + + type + TGenericSeq = object + len, reserved: int + PGenericSeq = ptr TGenericSeq + + when defined(gcRefc): + cast[PGenericSeq](x).len = 10 + else: + cast[ptr int](addr x)[] = 10 + + doAssert x == @[1, 2, 3, 4, 45, 56, 67, 999, 88, 777]