www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 21981] New: Manually calling a __dtor can violate memory safety


          Issue ID: 21981
           Summary: Manually calling a __dtor can violate memory safety
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: thomas.bockman gmail.com

The purpose of destructors is to describe cleanup work to be performed when the
lifetime of an object is over. Allowing  safe code to call a destructor
manually before that point and then continue to use the destroyed object
afterwards breaks RAII memory management:

module app;

import core.stdc.stdlib : malloc, free;

struct UniqueInt {
    private int* target;
    this(const(bool) doCreate) scope  trusted nothrow  nogc {
        target = cast(int*) malloc(int.sizeof);
        *target = 5;
     disable this(this);
     disable this(ref typeof(this));
     disable ref typeof(this) opAssign(ref typeof(this));

    void withBorrow(void delegate(scope int*)  safe action)  safe {
        action(target); }

    ~this() scope  trusted nothrow  nogc {
        if(target !is null) {
            target = null;

UniqueInt unique;
shared static this() {
    unique = true; }

void main()  safe {
    import std.stdio: writeln;

    unique.withBorrow((scope int* borrowed)  safe {
        writeln(*borrowed); // Use after free.

I think the only reasonable solution to this is to make calling __dtor,
__xdtor, or destroy manually an  system operation, regardless of the attributes
of ~this().

(I suspect there is some way to violate memory safety or break the type system
with this even in 100%  safe code, but I couldn't figure out what it is so I've
marked this as an enhancement request.)

Forum thread:
    https://forum.dlang.org/post/tkxneqmsbxfpomlnekhv forum.dlang.org

May 26 2021