Issue 19173 - [scope][dip1000] Using a `lazy` parameter defeats scope and dip1000
Summary: [scope][dip1000] Using a `lazy` parameter defeats scope and dip1000
Status: RESOLVED INVALID
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86_64 Linux
: P1 major
Assignee: No Owner
URL:
Keywords: safe
Depends on:
Blocks:
 
Reported: 2018-08-16 20:28 UTC by Atila Neves
Modified: 2019-09-23 09:19 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Atila Neves 2018-08-16 20:28:57 UTC
This code correctly does not compile:

-------------------------------------
@safe:

void main() {
    auto oops = Oops(10);
    Oops(10).should == oops[];
}

struct Oops {

    import core.stdc.stdlib;

    private int* _ints;
    private int size;

    this(int size) @trusted { this.size = size; _ints = cast(int*) malloc(size); }
    ~this() @trusted scope { free(_ints); }
    bool opEqual(ref const(Oops) other) const { return size == other.size; }
    scope auto opSlice(this This)() @trusted { return _ints[0 .. size]; }
}


auto should(E)(lazy E expr) {
    struct Should {
        bool opEquals(int[] ints) {
            assert(expr()[] == ints);
            return true;
        }
    }

    return Should();
}
-------------------------------------


escape_lazy.d(22): Error: variable `escape_lazy.should!(Oops).should.expr` has scoped destruction, cannot build closure
escape_lazy.d(22): Error: variable `escape_lazy.should!(Oops).should.expr` has scoped destruction, cannot build closure


Nice. However, slicing the rvalue defeats the compiler check and running under asan confirms that the resulting code has a use-after-free bug:

`Oops(10)[].should == oops[];`

As can be seen in the code above, making opSlice return a scope slice didn't seem to affect anything.