Jump to page: 1 2
Thread overview
Is @trusted the wrong direction?
Nov 09, 2019
Jesse Phillips
Nov 09, 2019
Jonathan M Davis
Nov 09, 2019
Alexandru Ermicioi
Nov 09, 2019
anon5886
Nov 10, 2019
Paolo Invernizzi
Nov 16, 2019
Alexandru Ermicioi
Nov 17, 2019
Paolo Invernizzi
Nov 18, 2019
Paolo Invernizzi
November 09, 2019
Trusted code is the gateway for safe code to call into system code. The code is suppose to indicate the layer for verify safe use of system code.

@safe
void main()
{
    foo();
}

@trusted
void foo () {
    auto fish = 5;
    auto m = &fish;
}

However the code itself is system code and the language does not restrict operations like in safe.

I'm wondering if trusted should operate in the same world as safe, with the benefit of calling @system code.

Now the concern would be that there would just be an additional system function between safe and the desired system code.

Would it make sense to analyze some existing trusted methods and suggest a change?
November 09, 2019
On 11/9/19 1:55 AM, Jesse Phillips wrote:
> Trusted code is the gateway for safe code to call into system code. The code is suppose to indicate the layer for verify safe use of system code.
> 
> @safe
> void main()
> {
>      foo();
> }
> 
> @trusted
> void foo () {
>      auto fish = 5;
>      auto m = &fish;
> }
> 
> However the code itself is system code and the language does not restrict operations like in safe.
> 
> I'm wondering if trusted should operate in the same world as safe, with the benefit of calling @system code.
> 
> Now the concern would be that there would just be an additional system function between safe and the desired system code.
> 
> Would it make sense to analyze some existing trusted methods and suggest a change?

I wrote an article about @trusted. It's definitely overused in a lot of places. I won't rehash what I said in the article, so please have a read. When to use @trusted is not always a straightforward and easy set of rules.

https://dlang.org/blog/2016/09/28/how-to-write-trusted-code-in-d/

-Steve
November 09, 2019
I always thought trusted functions shouldn't be a thing. Almost never a whole function need to be trusted, but only a few lines of code. What we need instead are trusted blocks. Those can be simulated with anonymous nested functions, but the syntax is ugly as hell while complete trusted functions should be forbidden.
November 09, 2019
On Saturday, November 9, 2019 9:22:05 AM MST Dominikus Dittes Scherkl via Digitalmars-d wrote:
> I always thought trusted functions shouldn't be a thing. Almost never a whole function need to be trusted, but only a few lines of code. What we need instead are trusted blocks. Those can be simulated with anonymous nested functions, but the syntax is ugly as hell while complete trusted functions should be forbidden.

Really, the fact that @trusted is at the function level is just an unnecessary complication. From the caller's perspective, @safe and @trusted are identical. Whether the function has been vetted for memory safety by the compiler or by a programmer doesn't matter to the caller. So, the fact that there's an API difference just causes problems (though fortunately, it's really just metaprogramming that's negatively affected by it).

I think that it would definitely be a good idea to add @trusted blocks of some kind to the language, but what that should look like is an open question. I also don't know how easy it would be to convince Walter to accept such a DIP, since I don't know what he currently thinks about the issue. For the moment, using @trusted lambdas is the best that we have, but yeah, it's ridiculously verbose and ugly. It also can cause bugs when you forget to call the lambda. Either way, using @trusted on non-lambda functions should usually be discouraged. Sometimes, it does make sense to use @trusted on large blocks of code, but most of the time, it doesn't, and it makes it a lot harder to figure out what exactly was @system that needed to be @trusted when a lot of code was @trusted at once.

- Jonathan M Davis



November 09, 2019
On Saturday, 9 November 2019 at 16:22:05 UTC, Dominikus Dittes Scherkl wrote:
> I always thought trusted functions shouldn't be a thing. Almost never a whole function need to be trusted, but only a few lines of code. What we need instead are trusted blocks. Those can be simulated with anonymous nested functions, but the syntax is ugly as hell while complete trusted functions should be forbidden.

Had an idea how to make more nice trusted blocks:

```d
import std.stdio;

T trusted (T)(T delegate() @system dg) @trusted {
   return dg();
}

void main() @safe
{
    writeln("Hello D");

    ({
        writeln("C ", cast(void*) 1);
    }).trusted;
}
```

looks a lot better than anonymous functions that are called right away after being defined.

Best regards,
Alexandru.
November 09, 2019
On Saturday, 9 November 2019 at 20:38:47 UTC, Alexandru Ermicioi wrote:
> ```d
> import std.stdio;
>
> T trusted (T)(T delegate() @system dg) @trusted {
>    return dg();
> }
>
> void main() @safe
> {
>     writeln("Hello D");
>
>     ({
>         writeln("C ", cast(void*) 1);
>     }).trusted;
> }
> ```
>
> looks a lot better than anonymous functions that are called right away after being defined.

Hmm. Only slightly better syntax, but more important doesn't solve the other half of the problem: Forbidding non-lambda trusted functions.

The syntax I would prefer for trusted blocks is simply

@trusted
{
}

And everything between the @trusted and the opening bracket (like function declarations) would be forbidden.
November 09, 2019
On Saturday, 9 November 2019 at 18:33:09 UTC, Jonathan M Davis wrote:
> Really, the fact that @trusted is at the function level is just an unnecessary complication. From the caller's perspective, @safe and @trusted are identical.
Yes. Three state enums are always clumsy, especially so if they are useless - and even not obviously so but you have to think about it every time to figure that out.

> Sometimes, it does make sense to use @trusted on large blocks of code, but most of the time, it doesn't,
Really almost never.

> and it makes it a lot harder to figure out what exactly was @system that needed to be @trusted when a lot of code was @trusted at once.
>
And even if that is really necessary, it would be no problem to declare a trusted block containing the whole function body. But from the outside the function is @safe, that's all that matters to the caller.
November 09, 2019
On Saturday, 9 November 2019 at 21:13:22 UTC, Dominikus Dittes Scherkl wrote:
> On Saturday, 9 November 2019 at 20:38:47 UTC, Alexandru Ermicioi wrote:
>> ```d
>> import std.stdio;
>>
>> T trusted (T)(T delegate() @system dg) @trusted {
>>    return dg();
>> }
>>
>> void main() @safe
>> {
>>     writeln("Hello D");
>>
>>     ({
>>         writeln("C ", cast(void*) 1);
>>     }).trusted;
>> }
>> ```
>>
>> looks a lot better than anonymous functions that are called right away after being defined.
>
> Hmm. Only slightly better syntax, but more important doesn't solve the other half of the problem: Forbidding non-lambda trusted functions.
>
> The syntax I would prefer for trusted blocks is simply
>
> @trusted
> {
> }
>
> And everything between the @trusted and the opening bracket (like function declarations) would be forbidden.

Implementation is trivial... I got tit to work in a small hour but the problem is that for now the safety really only works at the function level so the function properties have to be patch for the duration of the trusted block.

If someone wants to play a bit:

---
From 8b4fc62610b54375b4824be28478dc11bd0023cf Mon Sep 17 00:00:00 2001
From: Me <Me@nowhe.re>
Date: Sun, 10 Nov 2019 00:27:25 +0100
Subject: [PATCH] Allow partial trusting of a BlockStatment

- prevent usage of trusted delegates
- allow to infere @safe on func template containing these blocks
- reduce the scope of the manual verification, supposed to be done for @trusted
---
 src/dmd/parse.d        | 23 ++++++++++++++++++++++-
 src/dmd/statement.d    |  1 +
 src/dmd/statementsem.d | 17 +++++++++++++++++
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/src/dmd/parse.d b/src/dmd/parse.d
index 04cfc34e3..a57224b55 100644
--- a/src/dmd/parse.d
+++ b/src/dmd/parse.d
@@ -5383,6 +5383,27 @@ final class Parser(AST) : Lexer

         switch (token.value)
         {
+        case TOK.at:
+            auto n = peek(&token);
+            // @trusted { }
+            // ---
+            // ScopeBlockStatement:
+            //      Attributes? BlockStatement
+            //
+            if (n.value == TOK.identifier && isBuiltinAtAttribute(n.ident) == STC.trusted
+                && peekNext2 == TOK.leftCurly)
+            {
+                nextToken();
+                nextToken();
+                AST.Statement r = parseStatement(flags);
+                if (r.stmt == AST.STMT.Scope)
+                {
+                    (cast(AST.ScopeStatement) r).stc = AST.STC.trusted;
+                    // printf("trusted block parsed...\n");
+                }
+                return r;
+            }
+            goto Ldeclaration;
         case TOK.identifier:
             {
                 /* A leading identifier can be a declaration, label, or expression.
@@ -5565,7 +5586,7 @@ final class Parser(AST) : Lexer
         case TOK.pure_:
         case TOK.ref_:
         case TOK.gshared:
-        case TOK.at:
+        //case TOK.at:
         case TOK.struct_:
         case TOK.union_:
         case TOK.class_:
diff --git a/src/dmd/statement.d b/src/dmd/statement.d
index ea05cb75a..4a081e5a9 100644
--- a/src/dmd/statement.d
+++ b/src/dmd/statement.d
@@ -1009,6 +1009,7 @@ extern (C++) class ScopeStatement : Statement
 {
     Statement statement;
     Loc endloc;                 // location of closing curly bracket
+    STC stc;                    // indicate the block temporary attributes, @trusted only

     extern (D) this(const ref Loc loc, Statement statement, Loc endloc)
     {
diff --git a/src/dmd/statementsem.d b/src/dmd/statementsem.d
index 9276ffddb..ab1f1d234 100644
--- a/src/dmd/statementsem.d
+++ b/src/dmd/statementsem.d
@@ -420,6 +420,9 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
     override void visit(ScopeStatement ss)
     {
         //printf("ScopeStatement::semantic(sc = %p)\n", sc);
+
+
+
         if (ss.statement)
         {
             ScopeDsymbol sym = new ScopeDsymbol();
@@ -427,6 +430,20 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             sym.endlinnum = ss.endloc.linnum;
             sc = sc.push(sym);

+            // patch the scope to apply a temporary trusting for @trusted { }
+            TypeFunction tf = sc.func ? sc.func.type.toTypeFunction() : null;
+            const TRUST tr = tf ? tf.trust : TRUST.init;
+            if (ss.stc == STC.trusted && tr != TRUST.init)
+            {
+                tf.trust = TRUST.trusted;
+                //printf("set block statement scope and parent func as trusted...\n");
+            }
+            scope(exit)
+            {
+                if (tf)
+                    tf.trust = tr;
+            }
+
             Statements* a = ss.statement.flatten(sc);
             if (a)
             {
--
2.17.2


---
November 10, 2019
On Saturday, 9 November 2019 at 23:44:06 UTC, anon5886 wrote:
> On Saturday, 9 November 2019 at 21:13:22 UTC, Dominikus Dittes Scherkl wrote:
>> On Saturday, 9 November 2019 at 20:38:47 UTC, Alexandru Ermicioi wrote:
>>> ```d
>>> import std.stdio;
>>>
>>> T trusted (T)(T delegate() @system dg) @trusted {
>>>    return dg();
>>> }
>>>
>>> void main() @safe
>>> {
>>>     writeln("Hello D");
>>>
>>>     ({
>>>         writeln("C ", cast(void*) 1);
>>>     }).trusted;
>>> }
>>> ```
>>>
>>> looks a lot better than anonymous functions that are called right away after being defined.
>>
>> Hmm. Only slightly better syntax, but more important doesn't solve the other half of the problem: Forbidding non-lambda trusted functions.
>>
>> The syntax I would prefer for trusted blocks is simply
>>
>> @trusted
>> {
>> }
>>
>> And everything between the @trusted and the opening bracket (like function declarations) would be forbidden.
>
> Implementation is trivial... I got this to work in a small hour but the problem is that for now the safety really only works at the function level so the function properties have to be patch for the duration of the trusted block.
>
I don't see a problem with that. It's exactly what I expected need to be done.
Cool. I'll test this.
>
> - prevent usage of trusted delegates
> - allow to infere @safe on func template containing these blocks
> - reduce the scope of the manual verification, supposed to be done for @trusted

November 10, 2019
On Saturday, 9 November 2019 at 20:38:47 UTC, Alexandru Ermicioi wrote:
> On Saturday, 9 November 2019 at 16:22:05 UTC, Dominikus Dittes Scherkl wrote:
>> I always thought trusted functions shouldn't be a thing. Almost never a whole function need to be trusted, but only a few lines of code. What we need instead are trusted blocks. Those can be simulated with anonymous nested functions, but the syntax is ugly as hell while complete trusted functions should be forbidden.
>
> Had an idea how to make more nice trusted blocks:
>
> ```d
> import std.stdio;
>
> T trusted (T)(T delegate() @system dg) @trusted {
>    return dg();
> }
>
> void main() @safe
> {
>     writeln("Hello D");
>
>     ({
>         writeln("C ", cast(void*) 1);
>     }).trusted;
> }
> ```
>
> looks a lot better than anonymous functions that are called right away after being defined.
>
> Best regards,
> Alexandru.

That's exactly the kind of stuff to avoid, in my opinion: for a code reviewer point of view, this is just obfuscation, while the author should write trusted code in the more pedantic and clear way, to facilitate the reviewer analysis.

The whole point, in trusted code, is bond to the fact that the code should just be just plain easy to manually be checked.

/Paolo




« First   ‹ Prev
1 2