@trust is an encapsulation method, not an escape

Atila Neves via Digitalmars-d digitalmars-d at puremagic.com
Fri Feb 6 06:00:23 PST 2015


FWIW, and now that I think I understand how @trusted is supposed 
to be used, the arguments are valid. But I also:

1. Agree with H S Teoh on the maintainability aspect. Depending 
on humans reviewing the code is never going to work out. And even 
if it did, subsequent edits might break everything. It's a lot 
harder to review a 2-line diff to an existing function for 
trustworthiness than the original one when it was first written. 
I've lost count of how many code reviews I've approved at work 
that introduced subtle crashy bugs. And let's face it, reviewing 
a @trusted D function is no different from reviewing C code.

2. Agree with Dicebot that reviewing a 50-line function and 
making sure it isn't naughty is quite hard. Not impossible, but 
hard to guarantee its safety.

Unfortunately, I have no suggestions on how to make it better. 
The "@safe block/local function in a @trusted function" idea 
sounds promising, but I don't know how well it'd work out in 
practice.

Atila


On Thursday, 5 February 2015 at 23:39:39 UTC, Walter Bright wrote:
> Consider the following code excerpted from std.array.join:
>
>   static U trustedCast(U, V)(V v) @trusted { return cast(U) v; }
>   return trustedCast!RetType(result);
>
> This is because the compiler would complain that the following 
> line would not be @safe:
>
>   return cast(RetType)(result);
>
> The rationale is "I know it's safe, so I'll create an @trusted 
> wrapper to eliminate the error." What comes next is "that's 
> cumbersome. How about a better syntax:"
>
>   trusted {
>      return cast(RetType)(result);
>   }
>
> ? It's the rationale behind "unsafe" blocks that appear in 
> other languages. It seems like a perfectly reasonable request.
>
> The trouble with it is, what if the cast is converting from an 
> integer to a pointer? That could lead to memory corruption. The 
> code allows a potentially memory corrupting operation to be 
> inserted into code that is otherwise @safe.
>
> The only way to deal with it is to then manually review 
> everything about 'RetType' and 'result' to prove to oneself 
> that it is not converting random bit patterns into pointers. In 
> other words, one is manually reviewing @safe code for memory 
> corruption errors.
>
> This is an abject failure of @safe, @trusted, and @system.
>
> The solution is to regard @trusted as a means of encapsulating 
> unsafe operations, not escaping them. Encapsulating them means 
> that the interface from the @trusted code is such that it is 
> usable from safe code without having to manually review the 
> safe code for memory safety. For example (also from std.array):
>
>   static void trustedMemcopy(T[] dest, T[] src) @trusted
>   {
>     assert(src.length == dest.length);
>     memcpy(dest.ptr, src.ptr, src.length * T.sizeof);
>   }
>
> I don't have to review callers of trustedMemory() because it 
> encapsulates an unsafe operation (memcpy) with a safe interface.
>
> The reason @trusted applies only to functions, and not to 
> blocks of code, is that functions are the construct in D that 
> provides an interface. Arbitrary blocks of code do not have a 
> structured interface. Adding @trusted { code } support will 
> encourage incorrect uses like the opening example. The 
> existence of @trusted blocks will require review of every line 
> of code in the function that encloses it, and transitively 
> every function that calls it!
>
> Adding @trusted as a function attribute, on the other hand, 
> only requires review of the function's interface to determine 
> if it is acceptable to use in safe code. Safety review of its 
> callers is unnecessary.



More information about the Digitalmars-d mailing list