@safe inference fundamentally broken

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Thu Jun 5 11:09:44 PDT 2014


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- at 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- at safe, first by making it a warning, enabled with -w. Then making it an  
error.

Thoughts?

-Steve


More information about the Digitalmars-d mailing list