June 16, 2021

On Wednesday, 16 June 2021 at 16:22:24 UTC, RazvanN wrote:

>

On Wednesday, 16 June 2021 at 16:17:28 UTC, GrimMaple wrote:

>

On Wednesday, 16 June 2021 at 15:58:23 UTC, RazvanN wrote:

>

On Wednesday, 16 June 2021 at 14:57:19 UTC, GrimMaple wrote:

>

With my approach, you can still cover as many code @safe as you want without lying to the end user about the function safety. IMHO, if you perform @trusted operations in a @safe function, the function cannot be called @safe .

But this is not true. As Paul Backus pointed out, you can still have
a @safe function that calls trusted functions. Your argument seems
to imply that @safe should never interact with @trusted code, which
to be honest will make it unusable.

It's already broken, so let's break it even more? :)

June 16, 2021
On Wednesday, 16 June 2021 at 13:25:09 UTC, Steven Schveighoffer wrote:
> [snip]
>
> If I were to design it today:
>
> - a @safe function could not call @trusted functions that gained implicit access to local data (i.e. inner functions, or non-static member functions from the same type).
> - a @trusted function would be mechanically checked just like @safe, but could have @system blocks in them (where you could call @system functions, or do @system-like behaviors).
>
> This at least puts the emphasis on where manual verification is required, but still has the compiler checking things I want it to check. Most times, I never want to write a fully marked @trusted function, because it's so easy to trust things you didn't intend to (like destructors).
>
> -Steve


I see what you're saying. I agree the @trusted function with the @system blocks within them is better than @safe functions with @trusted blocks, all else equal. The downside is that the only way to do it without breaking code is to introduce an alternative to @trusted since @safe checking for @trusted would break code.

However, consider if you can have @safe/@trusted/@system blocks (such that a @safe block does manual checking). In that case, you could have something like below
@trusted
{
    @safe
    {
        // some safe code that you want manually checked
        //...
        @trusted
        {
            @system
            {
                // some @system code
            }
            // some @trusted code using the @system code
        }
    }
    // some other trusted code
}
June 16, 2021

On Wednesday, 16 June 2021 at 16:11:46 UTC, Paul Backus wrote:

>

You cannot tell just from looking at the signatures.

Then why is there the difference in the interface?

June 16, 2021

On Wednesday, 16 June 2021 at 16:32:01 UTC, GrimMaple wrote:

>

It's already broken, so let's break it even more? :)

Yes, why not. @safe, @trusted, @system is one of the more bizarre things in D. It kind of remind me of protection rings 0-3 in the X86 ISA. Few use all of these rings and just use two of them in order to separate kernel from user code. They are just there consuming gates and power.

ImportC seems to make this even more confusing, what are functions imported with ImportC going to be designated? @safe, @trusted, @system? If they they are labelled @safe, then it's kind of a lie and the programmer is responsible for knowing which function is FFI and what is not. If it is @system, then we need trampoline functions in D for every function if you are going to call it from safe, which kind of defeats the purpose of ImportC. @trusted might be the middle road but it is like @safe.

@system blocks in my opinion is an improvement and we can do away with @trusted because what's the point with it.

June 16, 2021
On Wednesday, 16 June 2021 at 15:37:22 UTC, H. S. Teoh wrote:
> On Wed, Jun 16, 2021 at 01:00:07PM +0000, kinke via Digitalmars-d wrote:
>> On Wednesday, 16 June 2021 at 11:38:54 UTC, RazvanN wrote:
>> > What do you think?
>> 
>> Absolutely love it, I've wanted this for ages, similar to C# `unsafe {}` blocks. I absolutely hate the trusted lambdas 'idiom'.
>
> This isn't the first time it was suggested.  Way back when, it was brought up and rejected because Walter thought that @trusted blocks should be discouraged, and therefore should be ugly to write.  It was extensively argued, but Walter preferred the "trusted lambda idiom", precisely because it was ugly, required effort to write, and therefore deters casual (ab)uses of @trusted.
>
>
> T

Yet, it forces to make entire function trusted if lambdas are not used, and safe guarantees are lost to remainder of the code due to that.

+1 for moving safety qualifiers to code blocks instead of functions.

Alex.
June 16, 2021

On Wednesday, 16 June 2021 at 16:32:01 UTC, GrimMaple wrote:

>

It's already broken, so let's break it even more? :)

It's not broken; you just don't understand it yet. I've written an article that goes through the whole thing step-by-step:

https://pbackus.github.io/blog/what-does-memory-safety-really-mean-in-d.html

June 16, 2021
On Wednesday, 16 June 2021 at 17:36:46 UTC, Alexandru Ermicioi wrote:
>
> Yet, it forces to make entire function trusted if lambdas are not used, and safe guarantees are lost to remainder of the code due to that.
>
> +1 for moving safety qualifiers to code blocks instead of functions.
>
> Alex.

I have a better idea, throw it all out. What is @safe? It's a limitation of operations you can do in D that might cause memory corruption, like pointer casts and such. Wouldn't be enough that the programmer self know about this and do not use those potentially harmful operations? That would be enough according to me but let's say that the programmer doesn't remember what is unsafe/safe. Then a compiler switch that gives a warning would be enough, at least for me.

I couldn't care less about this safe/unsafe and it just gets in the way. It is also clear that despite you want to automate safe code verification, you are unable to do so and the responsibility falls to the programmer anyway. That you are unable to solve how FFI should act (remember the famous DIP 1028) is also a reminder of that.
June 16, 2021
On Wed, Jun 16, 2021 at 05:36:46PM +0000, Alexandru Ermicioi via Digitalmars-d wrote:
> On Wednesday, 16 June 2021 at 15:37:22 UTC, H. S. Teoh wrote:
[...]
> > This isn't the first time it was suggested.  Way back when, it was brought up and rejected because Walter thought that @trusted blocks should be discouraged, and therefore should be ugly to write.  It was extensively argued, but Walter preferred the "trusted lambda idiom", precisely because it was ugly, required effort to write, and therefore deters casual (ab)uses of @trusted.
[...]
> Yet, it forces to make entire function trusted if lambdas are not used, and safe guarantees are lost to remainder of the code due to that.

Yeah, that's a flaw that ought to be fixed.  Marking an entire function @trusted is generally a bad idea, unless it's a trivial function of 3-4 lines or less, because it turns off ALL safety checks in the function body.  If the function is large, that's an onerous burden to review whether or not the code is indeed trustworthy.  What we really want is to keep those checks on except for the few bits of code that the compiler cannot automatically verify.

This has also been suggested before, and people are saying it again (and
in principle I agree):

1) Change the meaning of @trusted such that in a @trusted function, @safe checks are NOT suppressed by default. Instead, a @trusted function allows @system blocks in its body where @safe checks are temporarily suspended.

2) @system blocks are NOT allowed inside a @safe function.

Here's the reasoning:

- @trusted marks the *entire* function tainted and needing to be
  reviewed -- this is necessary because the safety of @system blocks
  therein often depends on the surrounding code context, and has to be
  reviewed in that larger context. It is not sufficient to review only
  the blocks containing @system code.

- Leaving @safe checks on outside @system blocks allows the @trusted
  function to be still mechanically checked to minimize human error.
  This allows the unchecked code to be confined to as small of a code
  block as possible.  Basically, limit the surface area of potential
  errors.

- We continue to maintain a difference between a @safe function and a
  @trusted function, because we do not want to allow @system blocks in a
  @safe function -- that would make @safe essentially meaningless
  (anybody can just throw in @system blocks in @safe code to bypass
  safety checks).  Such escapes are only allowed if the entire function
  is marked @trusted, making it clear that it potentially does something
  unsafe and therefore needs careful scrutiny.


T

-- 
One Word to write them all, One Access to find them, One Excel to count them all, And thus to Windows bind them. -- Mike Champion
June 16, 2021
On Wed, Jun 16, 2021 at 05:59:19PM +0000, IGotD- via Digitalmars-d wrote: [...]
> I have a better idea, throw it all out. What is @safe? It's a limitation of operations you can do in D that might cause memory corruption, like pointer casts and such. Wouldn't be enough that the programmer self know about this and do not use those potentially harmful operations? That would be enough according to me but let's say that the programmer doesn't remember what is unsafe/safe. Then a compiler switch that gives a warning would be enough, at least for me.

This is a gross misunderstanding of @safe.

The whole point of @safe is to minimize human error.  Trusting the programmer to know better is what led to C's design with all of its security holes.  Why bother with array length when we can just trust the programmer to do the right thing?  Why not just pass bare pointers around and freely cast them to/from void*, since the programmer ought to know whether it's safe?

The last several decades of security flaws involving buffer overflows, memory corruption, and all of that nice stuff is proof that the programmer CANNOT be trusted.  Programs are too complex for a human to write flawlessly.  We need to mechanically verify that stuff is safe so that (most) human errors are caught early, before they get deployed to production and cause massive damage.

Of course, due to Turing completeness and the halting problem, you can never mechanically verify 100% of the code.  Especially in system code, sometimes you DO need to trust that the programmer knows what he's doing. E.g., if you want to write a GC.  So sometimes you need an escape hatch to allow you to go outside the @safe box.

The whole idea behind @safe/@trusted/@system is that you want to allow the human to go outside the box sometimes, but you want to *minimize* that in order to reduce the surface area of potential human error. So most code should be @safe, and only occasionally @trusted when you need to do something the compiler cannot mechanically check.

IOW, reduce the room for human error as much as possible. Even if we can never eliminate it completely, it's better to minimize it rather than do nothing at all.


> I couldn't care less about this safe/unsafe and it just gets in the way.

If you don't care about @safe, then why not just write @system code? @system code is allowed to freely call into @safe without any restrictions.  You won't even need to know @safe exists if you don't use it.


> It is also clear that despite you want to automate safe code verification, you are unable to do so and the responsibility falls to the programmer anyway.  That you are unable to solve how FFI should act (remember the famous DIP 1028) is also a reminder of that.

This is not an an all-or-nothing binary choice.  *Ideally* we want to mechanically verify everything.  But since that's impossible (cf. halting problem), we settle for mechanically verifying as much as we can, and leave the rest as @trusted blocks that require human verification.  It's a practical compromise.  It's proven that mechanical checks DO catch human errors, even if they won't catch *all* of them. It's better to catch *some* of them than none at all (cf. the past, oh, 30+ years of security exploits caused by C/C++'s lack of automated checks?).


T

-- 
MAS = Mana Ada Sistem?
June 16, 2021
On 16.06.21 13:38, RazvanN wrote:
> 
> 
> What do you think?

@trusted nested functions are an antipattern and this enshrines them in a language feature.