Bug 18029 – extra dtor call with typed variadic argument (or missing postblit)

Status
NEW
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
x86
OS
All
Creation time
2017-12-04T06:57:48Z
Last change time
2024-12-13T18:55:13Z
Assigned to
No Owner
Creator
Ketmar Dark
Moved to GitHub: dmd#17822 →

Comments

Comment #0 by ketmar — 2017-12-04T06:57:48Z
the following code failing the assertion: === int rc = 0; struct S { int n; this (int na) { ++rc; n = na; import core.stdc.stdio; printf("ctor for (n=%d)\n", n); } this (this) { if (n) ++rc; import core.stdc.stdio; printf("postblit for (n=%d)\n", n); } ~this () { if (n) --rc; import core.stdc.stdio; printf("dtor for (n=%d)\n", n); n = 0; } } void test0 (S[] vals...) { vals[0] = S.init; //(1) this causes the bug } void test1 () { auto a0 = S(1); test0(a0); } void main () { test1(); assert(rc == 0); } === `dtor for (n=1)` is called twice, but only if (1) is not commented. comment out (1), and the bug is gone. *technically* calling dtor on already destructed struct is not a bug. but IRL it will ruin any reference counting scheme. tbh, i don't know how to fix this... let's say "corner case" without loosing performance. also, i dont' know why `a0` isn't cleared by `vals[0] = S.init;`. i thought that typed vararg just creates a slice of program stack, and assigning `.init` to `vals` member should clear `a0`. either that, or compiler should call postblit for each typed vararg member (please, no! ;-). so, this can be "missing postblit call" case too. i put both in subj until we'll decide what should be done in this case. please note that i'm clearing `n` in dtor, so calling dtor on already "destroyed" struct should not be disasterous. but somehow `a0` is not cleared.
Comment #1 by ilya.yanok — 2024-11-20T14:28:22Z
The arguments are most definitely copied, one can easily see that by taking the addresses of `vals[0]` and `a0` respectively. The spec is also pretty clear that the contents of the array is invalid after the function exits, see 5. here: https://docarchives.dlang.io/v2.076.0/spec/function.html#typesafe_variadic_functions So, that a0 remains unchanged is not really a mystery. It is weird though, that neither copy constructor nor postblit is called (I tried adding a copy constructor), probably some kind of optimization? But should we require typed varargs to always be const then? Then, the default opAssign calls the destructor on the lvalue being assigned. That seems to be correct, but since the value was never constructed, this causes a disparity in constructor/destructor calls you observe.
Comment #2 by robert.schadek — 2024-12-13T18:55:13Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/17822 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB