@trusted considered harmful

Artur Skawina art.08.09 at gmail.com
Sat Jul 28 09:23:14 PDT 2012


On 07/28/12 17:05, David Nadlinger wrote:
> On Saturday, 28 July 2012 at 11:05:34 UTC, Artur Skawina wrote:
>> On 07/28/12 02:08, David Nadlinger wrote:
>>> @trusted in its current form needs to go. Its design is badly broken, as it leaks implementation details and encourages writing unsafe code.
>>
>> The problem with @trusted is that it is transitive.
>>
>> @trusted should allow unsafe operations in the covered scope (right now -
>> the function), but disallow calling unsafe (@system) code. IOW a @safe
>> function should only be able to call a @safe or @trusted one, and the same
>> restriction should apply to @trusted functions. This way you can actually
>> audit the code - something which isn't typically possible right now, when
>> you have no control over what the "trusted" code might call.
> 
> Sorry, while I think I know which problem you are referring to, I don't see what your suggestion does to address it. There is no such thing as allowing unsafe code »only in the current scope«. As soon as you are allowed to do unsafe things, you can e.g. just cast a @system function to @safe and call it. Or jump to it using inline assembly, etc.

Of course inside a @trusted scope you will always be able to bypass every restriction.
But that does not mean that all restrictions should be disabled by default, so that
you are not able to take advantage of them and have to reimplement them by hand, like
checking if every called function is 'safe'.

> My suggestion might not be perfect, but it addresses the problem by allowing you to trust only the specific piece of your code which actually need to perform unsafe things. Reviewers can concentrate on the smaller sections to make sure that what they do is indeed @safe (e.g. that they don't call unsafe external code), and if something unsafe is accidentally done outside, the compiler will catch it.

Well, what you're proposing is already possible (other than the scope-lessness), your
suggestion would result in a nicer syntax. Which would be an improvement, I agree. but
it's not really enough.  Say somebody writes a function like this one:

   struct S { size_t m() @safe { return 42; } }

   T* t(T)(T* p, size_t idx) {
      auto s = p+idx;
      auto i = s.m();
      return p+i;
   }

then later realizes it can't be called from @safe code. The easiest solution will
be to mark the 't' function is trusted, which will work.

   T* t(T)(T* p, size_t idx) @trusted {
      auto s = p+idx;
      auto i = s.m();
      return p+i;
   }

Until 't' (much) later gets called with a different struct

   struct U { size_t m()  { return 666; } }

Which will succeed and @system code will silently run in a @safe context;
w/o even a warning.

What should have happened is that the function, instead of being marked as
@trusted, should have been rewritten as:

   T* t(T)(T* p, size_t idx) @safe {
      @trusted gets() { return p+idx; }
      auto s = gets();
      auto i = s.m();
      @trusted getn(size_t i) { return p+i; }
      return  getn(i);
   }

But, realistically, that is not what's going to happen most of the time...

Your suggestion is an improvement, in that it makes the above look like:

   T* t(T)(T* p, size_t idx) @safe {
      @trusted { auto s = p+idx; }
      auto i = s.m();
      @trusted { return p+i; }
   }

which is much better. But I'm afraid marking the whole function as trusted
will still be the 'easier' choice - so the problem won't go away, just become
less frequent.
Accidentally 'breaking' @safeness is a serious problem, at least if @safe is to
be taken seriously.

> I also think implementing your suggestion, i.e. distinguishing between »local« and »external« code, would add much value for another reason: In my experience, the most frequent use case for @trusted is precisely to interface with external code that is @system, either for legacy reasons of because it just can't be safe in the general case (e.g. grep the Phobos sources for @trusted). It seems like the actual low-level pointer/inline asm magic is often encapsulated into separate (@system) functions anyway.
> 
>> The '@attribute {}' syntax is something that is needed, but should probabl
>> wait for /proper/ attribute handling, which should also allow for a saner
>> 'synchronized' etc.
> 
> What is »proper attribute handling« supposed to be? How would it influence the implementation of @trusted{}? How is synchronized related to @trusted?

There have been some discussions about attributes in the past on these lists. I
have some thoughts on »proper attribute handling«, but that's a different topic.
What I mean here is that the /syntax/ could also be used for marking scopes/blocks
with other attributes besides @trusted; synchronized is an example that would also
fit in the '@attr {...}' scheme and is interesting because that also needs an
optional declaration block. 

artur


More information about the Digitalmars-d mailing list