@trusted attribute should be replaced with @trusted blocks

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Jan 16 20:47:54 UTC 2020


On Thu, Jan 16, 2020 at 02:18:09PM -0500, Steven Schveighoffer via Digitalmars-d wrote:
> On 1/16/20 1:08 PM, Joseph Rushton Wakeling wrote:
[...]
> > For example, in a class or struct implementation where a private
> > variable can be accessed by both @safe and @trusted methods ... ?
> 
> A recent example was a tagged union [1]. The tag is just an integer or
> boolean indicating which member of the union is valid. As long as the
> tag matches which actual element of the union is valid, you can use
> trusted functions to access the union member.
> 
> However, safe code is able to twiddle the tag without the compiler
> complaining. The trusted code is expecting the link between the union
> member that is valid and the tag. In other words, you can muck with
> the tag all day long in @safe land, even in a completely @safe
> function. But it may violates the assumptions that the @trusted
> functions make, making the other parts unsafe.

Good example!  So in this case, the trust really is between the tag and
the union, not so much in the @trusted function itself. The @trusted
function is really just *assuming* the validity of the correspondence
between the tag and the union.  Without encoding this context somehow,
the compiler cannot guarantee that some outside code (@safe code, no
less!) won't break the invariant and thereby invalidate the @trusted
function.


> Therefore, you have to review the whole type, even the safe calls, to
> make sure none of them violates the invariant.

:-(  And I guess this extends to any type that has @trusted methods that
make assumptions about the data stored in the type.  Which logically
leads to the idea that the data itself should be tagged somehow, and
therefore your idea of tagging the *data*.


[...]
> The other option is to somehow use the compiler to enforce the
> semantic, like marking the *data* @system. In other words you are
> telling the compiler "I know that it's normally safe to change this
> tag, but in this case, you can't, because it will mess things up
> elsewhere".
[...]

So it's basically a way of tainting any code that touches the data, such
that you're not allowed to touch the data unless you are @system or
@trusted.

This actually makes a lot of sense, the more I think about it. Take a
pointer T*, for example. Why is it illegal to modify the pointer (i.e.
do pointer arithmetic with T*) in @safe code? The act of changing the
pointer doesn't in itself corrupt memory.  What corrupts memory is when
the pointer is changed in a way that *breaks assumptions* laid upon it
by @safe code, such that when we subsequently dereference it, we may end
up in UB land.  We may say that pointer dereference is @trusted, in the
same sense as the tagged union access you described -- it's assuming
that the pointer points to something valid -- and our pointer arithmetic
has just broken that assumption.

Similarly, it's illegal to manipulate the .ptr field of an int[] in
@safe code: not because that in itself corrupts memory, but because that
breaks the assumption that an expression like int[i] will access valid
data (provided it's within the bounds of .length).  Again, the
manipulation of .ptr is @system, and array dereference with [i] is
@trusted in the same sense as tagged union access: arr[i] *assumes* that
there's a valid correspondence between .ptr, .length, and whatever .ptr
points to.

If therefore we prohibit manipulating .ptr in @safe code but allow
arr[i] (which makes assumptions about .ptr), then it makes sense to
prohibit manipulation of the tagged union's tag field and allow the
@trusted member to look up union fields.  It could even be argued that
union field lookup ought to be @safe in the same way arr[i] is @safe: it
won't corrupt memory or read out-of-bounds, contingent upon the
assumptions laid on an int[]'s .ptr and .length fields not to have been
broken.

IOW, we're talking about "sensitive data" here, i.e., data that must not
be modified in the wrong ways because it will break assumptions that
other code have laid upon it. Manipulating pointers is @system because
pointers are sensitive data. Manipulating ints is @safe because ints are
not sensitive data. In the same vein, the tag field of a tagged union is
sensitive data, and therefore manipulating it must be @system, i.e.,
only a @trusted function ought to be allowed to do that.

By default, @safe comes with its own set of what constitutes sensitive
data, and operations on such data are rightfully restricted.  Allowing
the user to tag data as sensitive seems to be a logical extension of
@safe.


T

-- 
It said to install Windows 2000 or better, so I installed Linux instead.


More information about the Digitalmars-d mailing list