Fix 21983 - Initialize remaining elements in a partially dup'ed array if postblit/copy ctor throws#3483
Conversation
|
Thanks for your pull request and interest in making D better, @MoonlightSentinel! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + druntime#3483" |
... if postblit/copy ctor throws This ensures deterministic behaviour in case of an exception and avoids dtor calls on uninitialized elements.
8362fdb to
074d810
Compare
|
Explicit destruction is not feasible due to the breakage caused by less-qualified constructors. |
| import core.internal.lifetime: emplaceInitializer; | ||
| // Initialize all remaining elements to not destruct garbage | ||
| foreach (j; i .. a.length) | ||
| emplaceInitializer(cast() arr[j]); |
There was a problem hiding this comment.
So you're resetting the element whose postblit/cpctor threw - should we?
There was a problem hiding this comment.
Yes, I think it's necessary because the GC will call the destructor for that element.
There was a problem hiding this comment.
My concern was that the postblit/cpctor might not clean up itself on an exception and depend on the dtor being run on the partially constructed instance. But that's hopefully handled by -preview=dtorfields, and resetting to T.init correct then. Maybe slightly adjust the comment to make that clear, to prevent someone from thinking it's a one-off bug as I did. ;)
There was a problem hiding this comment.
Isn't the correct thing instead for copyEmplace to reset its destination to T.init on failure, then this loop would be from i + 1? And same for some of the other emplace functions?
Otherwise this fix needs to be done in a bunch of other places because it would mean copyEmplace always needs a try/catch or scope(failure) to use safely if it might throw.
There was a problem hiding this comment.
Yes, that seems to make a lot of sense. After all, regular instances failing their construction aren't destructed, so postblit/cpctor cannot rely on the dtor being run in case they throw. - Maybe just using a try / catch(Exception) to prevent the overhead for nothrow postblits/cpctors/ctors.
There was a problem hiding this comment.
This ensures deterministic behaviour in case of an exception and
avoids dtor calls on uninitialized elements.