December 13, 2022
On Tuesday, 13 December 2022 at 00:56:12 UTC, Siarhei Siamashka wrote:
> On Monday, 12 December 2022 at 23:48:58 UTC, areYouSureAboutThat wrote:
>> So how about a compile time, commandline switch, that (warns or fails) when @safe code is calling @trusted code?
>>
>> Basically, I'm, saying to the compiler -> "if it's not @safe, I do not 'trust' it."
>
> Then you will have this warning in pretty much every application. Because any @safe code eventually ends up doing OS kernel API calls to show stuff on your screen or save it to a hard drive. The bridge from @safe to @system has to be crossed somewhere and the code annotated as @trusted works as such bridge.
>

you mean like this:

https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0227

December 13, 2022
On Tuesday, 13 December 2022 at 01:35:48 UTC, areYouSureAboutThat wrote:
>
> you mean like this:
>
> https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0227

and this:

https://doc.rust-lang.org/error_codes/E0133.html
December 13, 2022

On Tuesday, 13 December 2022 at 01:35:48 UTC, areYouSureAboutThat wrote:

>

On Tuesday, 13 December 2022 at 00:56:12 UTC, Siarhei Siamashka wrote:

>

On Monday, 12 December 2022 at 23:48:58 UTC, areYouSureAboutThat wrote:

>

So how about a compile time, commandline switch, that (warns or fails) when @safe code is calling @trusted code?

Basically, I'm, saying to the compiler -> "if it's not @safe, I do not 'trust' it."

Then you will have this warning in pretty much every application. Because any @safe code eventually ends up doing OS kernel API calls to show stuff on your screen or save it to a hard drive. The bridge from @safe to @system has to be crossed somewhere and the code annotated as @trusted works as such bridge.

you mean like this:

https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0227

I mean like this:

import std.stdio;
void main() @safe {
  writeln("Hello, world!");
}
$ dmd -g hello.d
$ gdb ./hello
(gdb) b write
(gdb) r
Breakpoint 1, 0x00007ffff7714bb0 in write () from /lib64/libc.so.6

(gdb) bt
#0  0x00007ffff7714bb0 in write () from /lib64/libc.so.6
#1  0x00007ffff7699ecd in _IO_file_write@@GLIBC_2.2.5 () from /lib64/libc.so.6
#2  0x00007ffff7699256 in new_do_write () from /lib64/libc.so.6
#3  0x00007ffff769af69 in __GI__IO_do_write () from /lib64/libc.so.6
#4  0x00007ffff769b393 in __GI__IO_file_overflow () from /lib64/libc.so.6
#5  0x0000555555557110 in std.stdio.File.LockingTextWriter.put!(char).put(char)
#6  0x00005555555563a0 in std.stdio.writeln!(immutable(char)[]).writeln(immutable(char)[])
#7  0x00005555555562e0 in D main () at ./hello.d:3

(gdb) disassemble
Dump of assembler code for function write:
=> 0x00007ffff7714bb0 <+0>:     mov    %fs:0x18,%eax
   0x00007ffff7714bb8 <+8>:     test   %eax,%eax
   0x00007ffff7714bba <+10>:    jne    0x7ffff7714bd0 <write+32>
   0x00007ffff7714bbc <+12>:    mov    $0x1,%eax
   0x00007ffff7714bc1 <+17>:    syscall
   0x00007ffff7714bc3 <+19>:    cmp    $0xfffffffffffff000,%rax
   0x00007ffff7714bc9 <+25>:    ja     0x7ffff7714c20 <write+112>
   0x00007ffff7714bcb <+27>:    ret

That's how you go from a @safe function main() down to a syscall instruction (then the rest is happening in the Linux kernel). Somewhere on this way a @trusted attribute needs to be used, which means "please @trust me, these particular potentially unsafe things are used correctly here and won't cause troubles": https://github.com/dlang/phobos/blob/v2.101.0/std/stdio.d#L3187

As the end users, we expect that Phobos interacts with a dangerous system library (libc) in a correct way. Phobos itself annotates trustedFPUTC/trustedFPUTWC functions imported from glibc as @trusted and expects that they are interacting with the OS kernel correctly without causing troubles.

It's impossible to do a syscall by using just @safe code and nothing else.

December 13, 2022
On Tuesday, 13 December 2022 at 02:45:29 UTC, Siarhei Siamashka wrote:
>
> It's impossible to do a syscall by using just `@safe` code and nothing else.

oh. so you mean syscalls and integrating with C is not safe? ;-)

My concern really is:

How do I know my @safe code is calling @safe code and not @trusted code?

@safe interfaces are nice - but all of Phobos could just as well be marked as @trusted, since @safe implicately trusts @trusted, and my @safe code would still compile just fine.

But when I -release it, I discover something that is not so welcome...cause all of that @trusted code is no longer subject to runtime memory safety checks.

I would like the compiler to tell me I'm calling code that has been marked as @trusted, and that if I want to proceed, then I need to compile with: -enableTrusted

That way, I've opted in to unsafety (i.e. @safe being allowed to use @trusted), rather than being defaulted in to it.
December 14, 2022

On Tuesday, 13 December 2022 at 01:50:26 UTC, areYouSureAboutThat wrote:

>

and this:

https://doc.rust-lang.org/error_codes/E0133.html

This isn't any different from D.

@system void f() { return; } // This is the unsafe code

@safe void main() {
    // error: `@safe` function `D main` cannot call `@system` function `app.f`
    f();
}

@safe void main() {
    () @trusted { f(); }(); // ok!
}

The difference is that D lets you also write

@trusted void main() {
    f(); // ok!
}

This is really just a nice shorthand for the @safe main with @trusted lambda inside. It's also a better practice, since @trusted in a function signature is easier to spot for a code reviewer than the lambda inside the function.

December 14, 2022

On Tuesday, 13 December 2022 at 05:26:23 UTC, areYouSureAboutThat wrote:

>

My concern really is:

How do I know my @safe code is calling @safe code and not @trusted code?

You can be sure that your @safe code is always calling at least some small amount of @trusted code inside of Phobos.

>

@safe interfaces are nice - but all of Phobos could just as well be marked as @trusted, since @safe implicately trusts @trusted, and my @safe code would still compile just fine.

Yes, it could be all marked as @trusted, but it isn't. Also Phobos or any other third-party library theoretically could do a lot of various bad things with or without @safe annotations. Some libraries have better code quality than the others and that's just how it is.

>

But when I -release it, I discover something that is not so welcome...cause all of that @trusted code is no longer subject to runtime memory safety checks.

If these @trusted parts of Phobos are bug free, then everything is fine. Your code shouldn't be able to trigger memory safety bugs in Phobos by feeding incorrect input to it.

>

I would like the compiler to tell me I'm calling code that has been marked as @trusted, and that if I want to proceed, then I need to compile with: -enableTrusted

As I already said before, you will effectively have to always use this switch for compiling each and every application.

I guess, you probably want the @trusted parts of Phobos to be annotated as @supertrusted and ignored by this switch, because it's the standard library deserving special privileges? And only complain about the @trusted attribute usage in your own code or in third-party libraries written by plebeians ;-)

December 14, 2022
On Wednesday, 14 December 2022 at 13:00:51 UTC, Siarhei Siamashka wrote:
>
> I guess, you probably want the @trusted parts of Phobos to be annotated as @supertrusted and ignored by this switch, because it's the standard library deserving special privileges? And only complain about the @trusted attribute usage in your own code or in third-party libraries written by plebeians ;-)

No. I do not 'trust' the standard library to be 'safe'. Why should I?

This is where a compiler switch would come in handy, as it could tell me when my @safe is calling @trusted, in the same way it does with @system and @nogc ....

That is, the compiler would help me discover that I might be relying on @trusted code somewhere down the chain, and that I should know about it.

As it is, I do not know unless I go examine the source code of Phobos.

The compiler switch could provide the assistance i need to go discover those parts mark as trusted.

Of course it could be optin, and as you point out, probably should be.

I guess I just need to work out how the compiler does it with @system and @nogc .. and adapt it to 'my needs', so I know @trusted code is being compiled into my library as well.
December 14, 2022
On Wednesday, 14 December 2022 at 11:45:02 UTC, Dukc wrote:
>
> This is really just a nice shorthand for the `@safe` main with `@trusted` lambda inside. It's also a better practice, since `@trusted` in a function signature is easier to spot for a code reviewer than the lambda inside the function.

The point of my referencing that link, is that you cannot compile in unsafe code into your library in Rust without (1) the compiler telling you, you can't do it unless.. or (2) you do what the compiler tells you.

That is, you cannot unknowingly compile in unsafe code into your library.

In D you can, since @trusted is no different from @system. It's just that @safe trusts @trusted. Therefore you have no way of knowing your getting @trusted (unsafe) in your library, as you do not need to annotate anything to get it. It just gets in there without you ever knowing.

Put simply, I would like to know when @trusted code is being compiled into my library..  hence my suggestion about an 'optin' compiler switch that tells you just that (as it currently does for @system, @nogc ...

December 14, 2022
On Wednesday, 14 December 2022 at 20:36:39 UTC, areYouSureAboutThat wrote:
> On Wednesday, 14 December 2022 at 13:00:51 UTC, Siarhei Siamashka wrote:
>>
>> I guess, you probably want the @trusted parts of Phobos to be annotated as @supertrusted and ignored by this switch, because it's the standard library deserving special privileges? And only complain about the @trusted attribute usage in your own code or in third-party libraries written by plebeians ;-)
>
> No. I do not 'trust' the standard library to be 'safe'. Why should I?

Earlier you posted this link: https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0227
Why do you 'trust' the standard library and VM of C# to be 'safe'?

December 14, 2022

On Wednesday, 14 December 2022 at 20:54:44 UTC, areYouSureAboutThat wrote:

>

On Wednesday, 14 December 2022 at 11:45:02 UTC, Dukc wrote:

>

This is really just a nice shorthand for the @safe main with @trusted lambda inside. It's also a better practice, since @trusted in a function signature is easier to spot for a code reviewer than the lambda inside the function.

The point of my referencing that link, is that you cannot compile in unsafe code into your library in Rust without (1) the compiler telling you, you can't do it unless.. or (2) you do what the compiler tells you.

That is, you cannot unknowingly compile in unsafe code into your library.

Dukc already explained it, but let me show some practical examples. Here's a buggy program in Rust:

use std::slice;

unsafe fn f(i: usize) -> i32 {
    let mut arr = [1, 2, 3];
    let s = slice::from_raw_parts_mut(arr.as_mut_ptr(), 1000);
    return s[i];
}

fn main() {
    unsafe { println!("{}", f(3)); } // ok!
}

And here's exactly the same buggy program converted to D:

@safe: import std;

@system int f(size_t i) {
    auto arr = [1, 2, 3];
    return arr.ptr[i];
}

void main() {
    () @trusted { writeln(f(3)); }(); // ok!
}

Both Rust and D compilers accept this code without complaining. Such code can be unknowingly compiled into your library. It may be a part of the standard library, or it may be a part of some third-party library that you want to use. And if the bug is difficult to reproduce, then you even won't be aware of it.

Now if you review the code, then D code is much more readable than Rust. If you want to find the boundary between safe and unsafe code in D, then you can just search for the "@trusted" attribute. But in Rust you can't easily find the boundary between safe and unsafe code, because the same "unsafe" keyword is reused for different purposes.

>

@trusted is no different from @system

It's is very different. If you look at a function as a black box without knowing what is inside, then:

  • @trusted function is typically safe to use. But this safety is guaranteed by human reviewers, because the compiler is not smart enough to do such analysis. It's important that the way how such functions are handling their input/output data is reasonably foolproof.

  • @system function may have some dangerous quirks and can be easily misused to shoot yourself in the foot (leak resources, segfault on incorrect input, deadlock when used from multiple threads, ...). It can be used correctly if the user is very careful, but allowing to call such function directly from the @safe code would be reckless.