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.

Reply via email to