August 05
What it means is functions that do @system things will have to be marked as @system or @trusted.

It kinda turns the attribute inference inside out :-/
August 05
On 7/30/2024 9:24 AM, Dukc wrote:
> ```D
> // unattributed
> extern(c) void free(void*);
> 
> // inferred as @safe!
> auto foo() => free(new int);
> ```

That's correct.

What we could do is require functions with no bodies to have an attribute.
August 05
On 7/30/2024 1:09 PM, Timon Gehr wrote:
> What is a characterization of those unattributed functions that are the root cause for any lack of memory safety in unattributed functions? Is it just `extern(C)` function prototypes? If so, that seems a bit weird.

Function prototypes can only be taken at face value. If they are unattributed, they would be accepted as callable from @safe code. Or we could simply say that prototypes would have to be explicitly attributed in order to be callable from @safe code.


> - calling a single `@system` function in an unattributed one would disable other safety checks in that unattributed function as it would then infer `@system`.

Not necessarily. But it would still require the caller to mark the function @trusted or @system.


> - there is still no way to enable safety checks in `@trusted` functions.

One can always switch it temporarily to @safe, fix any errors, then put it back.

But in general, trusted code should be a very small part of a program.
August 12
On Tuesday, 6 August 2024 at 00:54:32 UTC, Walter Bright wrote:
> On 7/30/2024 1:09 PM, Timon Gehr wrote:
>> What is a characterization of those unattributed functions that are the root cause for any lack of memory safety in unattributed functions? Is it just `extern(C)` function prototypes? If so, that seems a bit weird.
>
> Function prototypes can only be taken at face value. If they are unattributed, they would be accepted as callable from @safe code. Or we could simply say that prototypes would have to be explicitly attributed in order to be callable from @safe code.
>
>
>> - calling a single `@system` function in an unattributed one would disable other safety checks in that unattributed function as it would then infer `@system`.
>
> Not necessarily. But it would still require the caller to mark the function @trusted or @system.
>
>
>> - there is still no way to enable safety checks in `@trusted` functions.
>
> One can always switch it temporarily to @safe, fix any errors, then put it back.
>
> But in general, trusted code should be a very small part of a program.

One thought I had that might be an incremental improvement on using @trusted during refactoring is the ability to add a 'reason' to the attribute (C++ does this for the function that are attributed nodiscard --[[nodiscard("some reason here")]].

e.g.

void foo() @trusted("Have not made this function safe yet, still refactoring")
{
    // Something not yet refactored to be safe

}

void bar() @trusted("Manually verified by code review to be safe on Aug. 12, 2024")
{
    Third_Party_Library_Function_With_Interface_We_Trust_or_Own();
}

@safe SafeFunction(){
  // Calling into 2 'trusted' functions
  foo();
  bar();
}

Some other notes:

- There would be no reason to add a 'reason' for @safe or @system code (@safe is verified by the compiler already, @system is known to be an 'unsafe' block of code).
- Compiler or tooling could dump out @trusted functions with an annotated reason (similar to 'deprecated' messages) to programmer.




August 13
On Monday, 12 August 2024 at 18:47:02 UTC, Mike Shah wrote:
> On Tuesday, 6 August 2024 at 00:54:32 UTC, Walter Bright wrote:
>> On 7/30/2024 1:09 PM, Timon Gehr wrote:
>>> What is a characterization of those unattributed functions that are the root cause for any lack of memory safety in unattributed functions? Is it just `extern(C)` function prototypes? If so, that seems a bit weird.
>>
>> Function prototypes can only be taken at face value. If they are unattributed, they would be accepted as callable from @safe code. Or we could simply say that prototypes would have to be explicitly attributed in order to be callable from @safe code.
>>
>>
>>> - calling a single `@system` function in an unattributed one would disable other safety checks in that unattributed function as it would then infer `@system`.
>>
>> Not necessarily. But it would still require the caller to mark the function @trusted or @system.
>>
>>
>>> - there is still no way to enable safety checks in `@trusted` functions.
>>
>> One can always switch it temporarily to @safe, fix any errors, then put it back.
>>
>> But in general, trusted code should be a very small part of a program.
>
> One thought I had that might be an incremental improvement on using @trusted during refactoring is the ability to add a 'reason' to the attribute (C++ does this for the function that are attributed nodiscard --[[nodiscard("some reason here")]].
>
> e.g.
>
> void foo() @trusted("Have not made this function safe yet, still refactoring")
> {
>     // Something not yet refactored to be safe
>
> }
>
> void bar() @trusted("Manually verified by code review to be safe on Aug. 12, 2024")
> {
>     Third_Party_Library_Function_With_Interface_We_Trust_or_Own();
> }
>
> @safe SafeFunction(){
>   // Calling into 2 'trusted' functions
>   foo();
>   bar();
> }
>
> Some other notes:
>
> - There would be no reason to add a 'reason' for @safe or @system code (@safe is verified by the compiler already, @system is known to be an 'unsafe' block of code).
> - Compiler or tooling could dump out @trusted functions with an annotated reason (similar to 'deprecated' messages) to programmer.

Best one yet:

extern(C) int f() @trusted("Implementation is marked @safe");
August 13
On Tuesday, 13 August 2024 at 15:44:45 UTC, Quirin Schroll wrote:
> Best one yet:
>
> extern(C) int f() @trusted("Implementation is marked @safe");

If I own the implementation, is this possible?  Call to f() would be ambiguous (See below example).

I think I get your sentiment though :) The 'reason' provided could be totally bogus -- BUT it will at least stand out for folks aiming for 100% @safe code.

Providing some mechanism to users to indicate if @trusted is being used as a bridge between @safe and @system code (intended use), or if @trusted is merely being used a temporary fix until you refactor cycles later could be useful.

I suppose you could also add your own User Defined Attribute (UDA) to indicate the state of the functions "safeness" as well though (e.g. @trusted int f() @("safe_eventually");) -- but that doesn't seem very robust.


---------------------------------------
  1 import std.stdio;
  2
  3 extern(C) int f() @trusted;
  4
  5 @safe int f(){
  6     return 42;
  7 }
  8
  9 void main(){
 10     f();
 11 }

safe.d(10): Error: `safe.f` called with argument types `()` matches both:
safe.d(3):     `safe.f()`
and:
safe.d(5):     `safe.f()`
Failed: ["/usr/bin/dmd", "-v", "-o-", "safe.d", "-I."]
---------------------------------------


August 13
On 8/6/24 02:54, Walter Bright wrote:
> On 7/30/2024 1:09 PM, Timon Gehr wrote:
>> What is a characterization of those unattributed functions that are the root cause for any lack of memory safety in unattributed functions? Is it just `extern(C)` function prototypes? If so, that seems a bit weird.
> 
> Function prototypes can only be taken at face value. If they are unattributed, they would be accepted as callable from @safe code.

That is not what the DIP says, and I think it is a really bad idea.

> Or we could simply say that prototypes would have to be explicitly attributed in order to be callable from @safe code.
> ...

That was my expectation from reading the DIP. My point was however more that unattributed functions will be perhaps not memory safe, but the only way to smuggle in something that is not memory safe in practice is via `extern(C)` prototypes, as all other checks appear to be present.

I think it is a bit weird to require `extern(C)` prototypes for this case of "unsafe unannotated". It would be better to be able to disable and enable safety checks in a more granular fashion.

> ...
> 
>> - there is still no way to enable safety checks in `@trusted` functions.
> 
> One can always switch it temporarily to @safe, fix any errors, then put it back.
> ...

One can actually not always do that. Think template instantiation.

> But in general, trusted code should be a very small part of a program.

`@system` and `@trusted` code is where all the remaining memory safety accidents happen.

Basically, the issue is the lack of orthogonality between safety checking and interface safety. It does not hold that just because your interface is not safe, your implementation does not care about catching bugs. Supporting linting use cases is quite cheap, as the checks are in the compiler anyway.
August 14

On Tuesday, 13 August 2024 at 20:24:17 UTC, Mike Shah wrote:

>

On Tuesday, 13 August 2024 at 15:44:45 UTC, Quirin Schroll wrote:

>

Best one yet:

extern(C) int f() @trusted("Implementation is marked @safe");

If I own the implementation, is this possible? Call to f() would be ambiguous (See below example).

I think I get your sentiment though :) The 'reason' provided could be totally bogus -- BUT it will at least stand out for folks aiming for 100% @safe code.

Providing some mechanism to users to indicate if @trusted is being used as a bridge between @safe and @system code (intended use), or if @trusted is merely being used a temporary fix until you refactor cycles later could be useful.

I suppose you could also add your own User Defined Attribute (UDA) to indicate the state of the functions "safeness" as well though (e.g. @trusted int f() @("safe_eventually");) -- but that doesn't seem very robust.

  1 import std.stdio;
  2
  3 extern(C) int f() @trusted;
  4
  5 @safe int f(){
  6     return 42;
  7 }
  8
  9 void main(){
 10     f();
 11 }

safe.d(10): Error: `safe.f` called with argument types `()` matches both:
safe.d(3):     `safe.f()`
and:
safe.d(5):     `safe.f()`
Failed: ["/usr/bin/dmd", "-v", "-o-", "safe.d", "-I."]
--- x.d
import std.stdio;
extern(C) void f() @safe {
    writeln("Hello World!");
}
--- y.d
extern(C) void f() @trusted;

void main()
{
    f();
}

You can try it on run.dlang.io

Of course you can't overload extern(C) functions in the same module, but you can have a prototype in one module and the implementation in another. Marking non-extern(D) prototypes as @safe should not be allowed and is frowned upon by me and others as the compiler has no safeguards against getting it wrong, i.e. having a @system implementation. For extern(D), attributes are part of mangling, so if you're getting those wrong, at least the linker errors.

1 2 3
Next ›   Last »