misplaced @trust?

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Thu Feb 5 08:50:18 PST 2015


Reading the thread in bug report 
https://issues.dlang.org/show_bug.cgi?id=14125 gets me thinking, perhaps 
@trusted is mis-designed.

At the moment, a @trusted function is the same as a @system function, 
but is allowed to be called from a @safe function. And that's it.

But a @trusted function may only need to be marked @trusted because of a 
few lines of code. So we now use this mechanism where we mark the 
@trusted portions with a lambda or static nested function, and call that 
internally, and mark the entire function @safe.

The benefit of this is, for the 90% of the code that is @safe, the 
compiler is used as a tool to check the @safe-ty of the function. For 
the 10% that isn't, we have contained it and marked it, and we can focus 
on that portion for scrutiny. This becomes EXTREMELY important when it 
comes to maintenance.

For example, if a @trusted function has some code added to it, the new 
code needs to be measured to see if it really is safe to call from a 
@safe function. This may be no easy feat.

At least with the @trusted inner function/lambda, you limit yourself to 
the code that has been marked as such, and you don't need to worry about 
the actual @safe code that is added to the function.

Or do you?... the problem with this mentality is interactions with data 
inside the @safe code after a @trusted function is called can still be 
subject to memory safety issues. An example (using static functions for 
clarity):

void foo() @safe
{
    static auto tmalloc(size_t x) @trusted {return (cast(int *)malloc(x 
* sizeof(int)))[0..x];}
    static void tfree(void[] arr) @trusted {free(arr.ptr);}

    auto mem = tmalloc(100);
    tfree(mem);
    mem[0] = 5;
}

Note that the final line in the function, setting mem[0] to 5, is the 
only unsafe part. it's safe to malloc, it's safe to free as long as you 
don't ever refer to that memory again.

But the problem with the above is that @trusted is not needed to apply 
to the mem[0] = 5 call. And imagine that the mem[0] = 5 function may be 
simply added, by another person who didn't understand the context. 
Marking the whole function as safe is kind of meaningless here.

Changing gears, one of the issues raised in the aforementioned bug is 
that a function like this really should be marked trusted in its 
entirety. But what does this actually mean?

When we mark a function @safe, we can assume that the compiler has 
checked it for us. When we mark a function @trusted, we can assume the 
compiler has NOT checked it for us. But how does this help? A @safe 
function can call a @trusted function. So there is little difference 
between a @safe and a @trusted function from an API point of view. I 
would contend that @trusted really should NEVER HAVE BEEN a function 
attribute. You may as well call them all @safe, there is no difference.

What I think we need to approach this correctly is that instead of 
marking *functions* with @trusted, we need to mark *data* and *calls* 
with @trusted. Once data is used inside a @trusted island, it becomes 
tainted with the @trusted mark. The compiler can no longer guarantee 
safety for that data.

So how can we implement this without too much pain? I envision that we 
can mark lines or blocks inside a @safe function as @trusted (a @trusted 
block inside a @system function would be a no-op, but allowed). I also 
envision that any variable used inside the function is internally marked 
as @safe until it's used in a @trusted block, and then is marked as 
@trusted (again internally, no requirement to mark in syntax). If at any 
time during compilation a @trusted variable is used in @safe code, it's 
a compile error.

There may be situations in which you DO need this to work, and in those 
cases, I would say a cast(@safe) could get rid of that mark. For 
example, if you want to return the result of a @trusted call in a @safe 
function.

Such a change would be somewhat disruptive, but much more in line with 
what @trusted calls really mean.

I've left some of the details fuzzy on purpose, because I'm not a 
compiler writer :)

Destroy

-Steve


More information about the Digitalmars-d mailing list