Comment #0 by thomas.bockman — 2021-03-08T23:42:27Z
The program below never destroys its extern(C++) class instances, breaking RAII. Output since 2.066:
Destroying stack D instance.
Destroying heap D instance.
The destructor should definitely be called for the `scope` instance, as it would be for a struct on the stack. The heap instance's destructor should also be called, OR trying to allocate an instance of an extern(C++) class that has a destructor on the GC heap using `new` should be a compile-time error.
/////////////////////////////////////
extern(C++) class C {
bool onStack;
this(bool onStack) {
this.onStack = onStack; }
~this() {
writeln("Destroying ", onStack? "stack" : "heap", " C instance."); }
}
extern(D) class D {
bool onStack;
this(bool onStack) {
this.onStack = onStack; }
~this() {
writeln("Destroying ", onStack? "stack" : "heap", " D instance."); }
}
void main() {
scope stackC = new C(true);
auto heapC = new C(false);
scope stackD = new D(true);
auto heapD = new D(false);
}
/////////////////////////////////////
Related: https://issues.dlang.org/show_bug.cgi?id=21692
Comment #1 by moonlightsentinel — 2021-03-11T02:52:31Z
@MoonlightSentinel updated dlang/dmd pull request #12265 "Issue 21693 - Lower scoped destruction of extern(C++) class to destroy" mentioning this issue:
- Issue 21693 - Lower scoped destruction of extern(C++) class to destroy
Ensures proper RAII behaviour for stack allocated instances but doesn't
affect the behaviour for heap allocated instances.
The previous rewrite used `delete` which relies on `TypeInfo` and
crashed at runtime. Using `object.destroy` circumvents this issue (and
is also beneficial due to the deprecation of `delete`).
`destroy` can be used instead of `delete` because the instances live on
the heap and hence don't need to be deallocated.
https://github.com/dlang/dmd/pull/12265
Comment #3 by kinke — 2021-03-13T21:34:48Z
The GC could presumably handle C++ classes like structs, where the TypeInfo_Struct pointer is stored after the struct instance IIRC. For C++ classes, it could store the D TypeInfo_Class pointer after the class instance (but note that class instances have no tail padding, so some padding might be needed for an aligned TypeInfo pointer).
Comment #4 by dlang-bot — 2021-03-15T06:34:28Z
dlang/dmd pull request #12265 "Issue 21693 - Lower scoped destruction of extern(C++) class to destroy/dtor call" was merged into stable:
- e28736c522d9c81acef9c66c1f02da4375f08207 by MoonlightSentinel:
Issue 21693 - Lower scoped destruction of extern(C++) class to destroy
Ensures proper RAII behaviour for stack allocated instances but doesn't
affect the behaviour for heap allocated instances.
The previous rewrite used `delete` which relies on `TypeInfo` and
crashed at runtime. Using `object.destroy` circumvents this issue (and
is also beneficial due to the deprecation of `delete`).
`destroy` can be used instead of `delete` because the instances live on
the heap and hence don't need to be deallocated.
- aa2147b836b129e835828a6e6faef363ed3255a8 by MoonlightSentinel:
fixup! Issue 21693 - Lower scoped destruction of extern(C++) class to destroy
https://github.com/dlang/dmd/pull/12265
Comment #5 by thomas.bockman — 2021-03-15T23:35:58Z
(In reply to kinke from comment #3)
> The GC could presumably handle C++ classes like structs, where the
> TypeInfo_Struct pointer is stored after the struct instance IIRC. For C++
> classes, it could store the D TypeInfo_Class pointer after the class
> instance (but note that class instances have no tail padding, so some
> padding might be needed for an aligned TypeInfo pointer).
That would be fine. The maximum overhead would be less than (size_t.sizeof * 2), which is no big deal if it gets RAII working properly.
Is it necessary to store a TypeInfo pointer for every instance, though? Garbage collected instances would all be allocated on the D side, so I would think that the TypeInfo data could just be stored adjacent to D's copy of the vtable.
Comment #6 by thomas.bockman — 2021-03-15T23:41:35Z
I'm dropping the priority from "critical" to "major" now that destruction is performed for `scope` instances, since the GC doesn't strictly guarantee deterministic destruction even for D class instances.
Thanks, @moonlightsentinel!
Comment #7 by dlang-bot — 2021-03-24T10:39:14Z
@puneet updated dlang/dmd pull request #12302 "Fix issue 19192 - [wrong-code] [crashes] Covariant method interface <…" mentioning this issue:
- Issue 21693 - Lower scoped destruction of extern(C++) class to destroy/dtor call (#12265)
* Issue 21693 - Lower scoped destruction of extern(C++) class to destroy
Ensures proper RAII behaviour for stack allocated instances but doesn't
affect the behaviour for heap allocated instances.
The previous rewrite used `delete` which relies on `TypeInfo` and
crashed at runtime. Using `object.destroy` circumvents this issue (and
is also beneficial due to the deprecation of `delete`).
`destroy` can be used instead of `delete` because the instances live on
the heap and hence don't need to be deallocated.
https://github.com/dlang/dmd/pull/12302
Comment #8 by dlang-bot — 2021-04-08T22:54:18Z
@MoonlightSentinel updated dlang/dmd pull request #12402 "Fix 21229 - Accept construction of union member as initialization" mentioning this issue:
- Issue 21693 - Lower scoped destruction of extern(C++) class to destroy/dtor call (#12265)
* Issue 21693 - Lower scoped destruction of extern(C++) class to destroy
Ensures proper RAII behaviour for stack allocated instances but doesn't
affect the behaviour for heap allocated instances.
The previous rewrite used `delete` which relies on `TypeInfo` and
crashed at runtime. Using `object.destroy` circumvents this issue (and
is also beneficial due to the deprecation of `delete`).
`destroy` can be used instead of `delete` because the instances live on
the heap and hence don't need to be deallocated.
https://github.com/dlang/dmd/pull/12402
Comment #9 by dlang-bot — 2021-04-09T08:07:29Z
@MoonlightSentinel created dlang/dmd pull request #12408 "Merge stable into master" mentioning this issue:
- Issue 21693 - Lower scoped destruction of extern(C++) class to destroy/dtor call (#12265)
* Issue 21693 - Lower scoped destruction of extern(C++) class to destroy
Ensures proper RAII behaviour for stack allocated instances but doesn't
affect the behaviour for heap allocated instances.
The previous rewrite used `delete` which relies on `TypeInfo` and
crashed at runtime. Using `object.destroy` circumvents this issue (and
is also beneficial due to the deprecation of `delete`).
`destroy` can be used instead of `delete` because the instances live on
the heap and hence don't need to be deallocated.
https://github.com/dlang/dmd/pull/12408
Comment #10 by dlang-bot — 2021-04-09T10:48:58Z
dlang/dmd pull request #12408 "Merge stable into master" was merged into master:
- 939778e46731edc6c4f726dda7f82aaa209d012e by Florian:
Issue 21693 - Lower scoped destruction of extern(C++) class to destroy/dtor call (#12265)
* Issue 21693 - Lower scoped destruction of extern(C++) class to destroy
Ensures proper RAII behaviour for stack allocated instances but doesn't
affect the behaviour for heap allocated instances.
The previous rewrite used `delete` which relies on `TypeInfo` and
crashed at runtime. Using `object.destroy` circumvents this issue (and
is also beneficial due to the deprecation of `delete`).
`destroy` can be used instead of `delete` because the instances live on
the heap and hence don't need to be deallocated.
https://github.com/dlang/dmd/pull/12408
Comment #11 by robert.schadek — 2024-12-13T19:15:04Z