I was just viewing an interesting pull request. The pull wanted to change a line like this (buf is a fixed-size stack allocated array):

auto x = buf.ptr[0..buf.len];

To this:

auto trustedBuffer(ref typeof(buf) b) @trusted { return b.ptr[0..buf.len]; }

for the sake of allowing the enclosing template function to be inferred @safe. But the interesting thing is that the original line is DELIBERATELY that way to PREVENT the compiler from inferring @safety (the buffer could potentially be squirreled away somewhere).

I questioned the idea of using the .ptr trick to fool the compiler, and asked why doesn't just do the correct thing. Turns out, the compiler is very bad at determining if stack-allocated data is escaped or returned.

A quick example:

T[] getBuf(T)() @safe
{
    T[100] ret;
    auto r = ret[];
    return r;
}

void main() @safe
{
    auto buf = getBuf!int();
}

Note, the above compiles. An interesting thing here is that we have explicitly marked getBuf as @safe. So what if we want to remove that? It STILL compiles, because the compiler infers @safety!

In order to fix it, we can either mark the function getBuf as @system, or do what was done in the original code above. The benefit of using ptr instead of @system is that it's much less susceptible to someone coming along and saying "hey look, if I just remove @system, it works!" It also allows conditionally compiled un-@safe code to be included in the same function, and let the compiler infer correctly.

But this is extremely alarming. Here we have to be vigilant for anything like this, and make SURE we explicitly mark this as @system. If there is some possibility that a function could be inferred @safe or @system depending on the template parameters, then we would need to write separate templates for both, or use the .ptr trick above.

This situation is very bad. I personally think that we need to make slicing a stack-allocated array INVALID in @safe code, and not let that code be inferred safe. We have already demonstrated an easy way to make an internal delegate that can be @trusted for one line. That should be used to work around this limitation.

I propose that we start migrating towards making slicing of stack data un-@safe, first by making it a warning, enabled with -w. Then making it an error.

Thoughts?

-Steve

Reply via email to