Bug 22680 – @safe hole with destructors

Status
RESOLVED
Resolution
FIXED
Severity
minor
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2022-01-16T19:58:40Z
Last change time
2022-09-05T07:31:10Z
Keywords
bootcamp, pull, safe
Assigned to
No Owner
Creator
elronnd

Comments

Comment #0 by elronnd — 2022-01-16T19:58:40Z
C c; class C { ~this() @safe { c = this; } } This is accepted, but is unsafe. I propose that destructors always be marked as 'scope'.
Comment #1 by razvan.nitu1305 — 2022-01-17T11:34:19Z
There is nothing unsafe in assigning a class reference to another. I agree that
Comment #2 by ag0aep6g — 2022-01-17T12:41:36Z
(In reply to RazvanN from comment #1) > There is nothing unsafe in assigning a class reference to another. Unless you're assigning garbage, which is happening here. A more elaborate demonstration of the unsafety: ---- import std.stdio: writeln; import core.memory: GC; C c; class C { immutable int* ip; this(int x) @safe { this.ip = new int(x); } ~this() @safe { c = this; } } void main() @safe { () { new C(42); } (); () { ubyte[1000] clear_stack; } (); () @trusted { GC.collect(); } (); immutable int* ip = c.ip; writeln(*ip); /* Prints "42". */ new int(13); int should_still_be_42 = *ip; writeln(should_still_be_42); /* Prints "13" - immutable data has changed. */ } ----
Comment #3 by razvan.nitu1305 — 2022-01-17T13:43:12Z
(In reply to ag0aep6g from comment #2) > (In reply to RazvanN from comment #1) > > There is nothing unsafe in assigning a class reference to another. > > Unless you're assigning garbage, which is happening here. A more elaborate > demonstration of the unsafety: > > ---- > import std.stdio: writeln; > import core.memory: GC; > C c; > class C > { > immutable int* ip; > this(int x) @safe { this.ip = new int(x); } > ~this() @safe { c = this; } > } > void main() @safe > { > () { new C(42); } (); > () { ubyte[1000] clear_stack; } (); > () @trusted { GC.collect(); } (); > immutable int* ip = c.ip; > writeln(*ip); /* Prints "42". */ > new int(13); > int should_still_be_42 = *ip; > writeln(should_still_be_42); /* Prints "13" - immutable data has > changed. */ > } > ---- My comment was unfinished. What I wanted to propose is to mark destructors that are @safe with scope. I don't think there would be any un-wanted side effects. I added some labels and I pushed "Save Changes", but I forgot that I had a comment started.
Comment #4 by stanislav.blinov — 2022-01-17T14:36:11Z
(In reply to RazvanN from comment #3) > My comment was unfinished. What I wanted to propose is to mark destructors > that are @safe with scope. I don't think there would be any un-wanted side > effects. > There would be unwanted side effects. On a struct, for example, marking a destructor scope would prevent you from returning instances of such struct. I think that a more prudent measure is to mark escaping destructors @system (i.e. making original code a compile-time error).
Comment #5 by dkorpel — 2022-03-29T13:24:53Z
(In reply to Stanislav Blinov from comment #4) > There would be unwanted side effects. On a struct, for example, marking a > destructor scope would prevent you from returning instances of such struct. No, it only adds restrictions to the destructor's function body, not the destructor's caller.
Comment #6 by stanislav.blinov — 2022-03-29T13:53:59Z
(In reply to Dennis from comment #5) > (In reply to Stanislav Blinov from comment #4) > > There would be unwanted side effects. On a struct, for example, marking a > > destructor scope would prevent you from returning instances of such struct. > > No, it only adds restrictions to the destructor's function body, not the > destructor's caller. Compile this with -dip1000: @safe: struct S { ~this() scope {} void* p; } S test() { S s; return s; // Error: scope variable `s` may not be returned } void main() { }
Comment #7 by dkorpel — 2022-03-29T14:12:44Z
(In reply to Stanislav Blinov from comment #6) > Compile this with -dip1000: That looks like a bug / remnant from the old dip1000 design.
Comment #8 by dkorpel — 2022-03-29T14:27:08Z
(In reply to Dennis from comment #7) > That looks like a bug / remnant from the old dip1000 design. Introduced by https://github.com/dlang/dmd/pull/7284
Comment #9 by stanislav.blinov — 2022-03-29T14:57:33Z
(In reply to Dennis from comment #7) > (In reply to Stanislav Blinov from comment #6) > > Compile this with -dip1000: > > That looks like a bug / remnant from the old dip1000 design. Oh, OK, that's good to know, thanks!
Comment #10 by bugzilla — 2022-08-31T02:30:04Z
(In reply to Stanislav Blinov from comment #6) > S test() > { > S s; > return s; // Error: scope variable `s` may not be returned > } This has been fixed.
Comment #11 by bugzilla — 2022-08-31T02:32:26Z
And so the way should be clear now for marking a destructor as `scope`.
Comment #12 by dlang-bot — 2022-08-31T19:34:41Z
@WalterBright created dlang/dmd pull request #14402 "fix Issue 22680 - @safe hole with destructors" fixing this issue: - fix Issue 22680 - @safe hole with destructors https://github.com/dlang/dmd/pull/14402
Comment #13 by dlang-bot — 2022-09-05T07:31:10Z
dlang/dmd pull request #14402 "fix Issue 22680 - @safe hole with destructors" was merged into master: - 4780baecbbccb3e1d5c8fb85ef6e34de4030c71c by Walter Bright: fix Issue 22680 - @safe hole with destructors https://github.com/dlang/dmd/pull/14402