Discussion Thread: DIP 1028--Make @safe the Default--Final Review

Timon Gehr timon.gehr at gmx.ch
Wed Apr 8 19:30:18 UTC 2020


On 08.04.20 15:09, Steven Schveighoffer wrote:
> On 4/7/20 10:01 PM, Timon Gehr wrote:
>> On 07.04.20 23:14, Steven Schveighoffer wrote:
>>> On 4/6/20 2:28 PM, Timon Gehr wrote:
>>>> On 06.04.20 01:38, Steven Schveighoffer wrote:
>>>>> I disagree with disallowing @safe as a specific marking on 
>>>>> extern(C) code. You can write @safe extern(C) functions in D, and 
>>>>> it makes no sense to require that they are @trusted at the prototype.
>>>>
>>>> The linker can hijack them. The function signature of a @trusted 
>>>> function should be @safe anyway.
>>>
>>> The linker can always hijack it.
>>
>> I guess I used the wrong word. What I meant was that there is zero 
>> checking that the extern(C) function you are calling was actually 
>> checked to be @safe. For extern(D), the language at least makes a 
>> small effort to ensure the @safe qualifier has some meaning, but given 
>> that return types are not mangled, that also seems like a lie.
> 
> If you change the return type, then there can be detectable differences 
> at runtime. If you change the @safe vs. @trusted vs. @system, everything 
> works *exactly* as before (unless the linker stops it).
> 
> The biggest problem is code that works but is wrong in terms of safety. 
> In that case, @safe and @trusted on prototypes are identical.
> ...

Wrong. In terms of _language_ and _type system_ design what's most 
important is that if code is marked @safe, is actually memory safe 
conditional on programmers getting the @trusted annotations right. 
That's the promise that the language is giving.

>>
>>> Even without intention. Having it marked @trusted isn't any better 
>>> than having it marked @safe in that case.
>>> ...
>>
>> Memory corruption in a @safe context should be traceable to @trusted 
>> code. It's the entire point.
> 
> And in this case, there is no trusted code.

You are trusting the prototype to be correct.

> It's all @safe, but you have 
> a boy-who-cried-wolf effect on the @trusted prototype. "Oh, you can 
> ignore those prototypes because the compiler made me do it." In fact I'm 
> assuming you will see stuff like:
> 
> // really @safe
> @trusted extern(C) ...
> 
> causing a reviewer to pass over those as possible problems.
> ...

And of course if the module has no @trusted code at all the reviewer 
will be extra careful?

> I'm not saying @safe marking of prototypes isn't prone to issues,

Purely @safe code is not supposed to be prone to issues.

> I'm saying forcing @trusted markings doesn't change that fact.
> ...

@trusted means "there may be issues here". @safe means "no issues here".

>>
>>>>
>>>>> Assuming @safe, no. Explicitly @safe OK, you marked it, you own it.
>>>>> ...
>>>>
>>>> @safe:
>>>>
>>>> // a lot of code
>>>> // ...
>>>>
>>>> extern(C) corrupt_all_the_memory();
>>>
>>> Why would you do this when @safe is the default?
>>> ...
>>
>> To show it's broken.
>>
>> Besides that, it's not currently the default, and if it is, you might 
>> want to temporarily switch to @system and back.
> 
> In that case, all is well! you properly marked the right ones @system.
> ...

So we're right back to trusting the programmer even though that 
programmer did not actually write any @trusted annotations.

> In the current regime, @safe: at the top does the same thing you are 
> trying to argue against. So there won't be existing (good) code that 
> does this.
> 
> In the new regime, @safe is the default, so you wouldn't need to put 
> @safe: at the top.
> ...

It does not have to be at the top of the file.

> Any time the compiler forces you to mark things differently than the 
> truth, you become more numb to these compiler warnings, and don't put 
> any stock into their significance.
> ...

@trusted is the truth, @safe is the lie.

>> In any case, @safe code by definition is code written by untrusted 
>> programmers. Why do you insist there should be a good reason? Maybe 
>> the programmer was a monkey. Or malicious.
> 
> @safe code is mechanically checked. Why shouldn't I be able to declare 
> that when it's true?

Because the prototype is not mechanically checked. Programmers who are 
not allowed to write @trusted code have no business writing @safe 
extern(C) prototypes.

> And if you make me mark it @trusted, and it for 
> some reason becomes @system (because it's not @trustable, a very 
> unlikely occurrence), having them marked @trusted doesn't help. You 
> still have to go find the prototypes (all of them) and mark them @system 
> instead.
> ...

It's the prototype maintainer's responsibility to ensure it does not happen.

>>
>>>>
>>>> When did @safe become a matter of "it's your own fault if you shoot 
>>>> yourself in the foot, this memory corruption you are having is a 
>>>> good thing because it will teach you not to make more mistakes in 
>>>> the future"? If something may break @safe-ty as it trusts the 
>>>> programmer to get it right, it ought to be @trusted.
>>>
>>> If you mark a @safe extern(C) function @trusted, how does that help? 
>>> I'm talking about extern(C) functions that are checked by the 
>>> compiler as @safe. Why should I have to mark the prototype of that 
>>> function @trusted?
>>
>> Because the extern(C) function can be changed to be @system. Hence you 
>> must trust the maintainer of the prototype to keep it in sync with the 
>> implementation.
> 
> So you are saying this scenario is OK:
> 
> Hm... my @safe function is turning into @system. But that's OK because 
> everyone had to mark their prototypes @trusted! So now it becomes their 
> fault I changed it.
> ...

It is their fault. Why did they make their @safety conditional on the 
signature of an extern(C) function that apparently was outside their own 
control?

> I don't get how this is helpful. I don't get how this is somehow 
> logically superior to the same people being able to mark the functions 
> @safe. In both cases, you are pulling the rug from underneath them.
> ...

But the code at the prototype is not lying about it.

> It sounds more like a "good" non-monkey programmer should mark all 
> extern(C) function prototypes @system, regardless of the actual safety 
> of the function, and require @trusted escapes, because they can change 
> at any time without warning and they might get blamed.

If that is in fact a possibility they should absolutely do that. 
Otherwise they need to have conventions in place that prevent it from 
happening. If the @safety of a piece of code is conditional on such 
conventions, it should be marked @trusted.

>> ...
> What if the @safe prototype is auto-generated? Then whenever it changes 
> to @system, the prototype will be changed. This means, you have a memory 
> issue, you search for @trusted, find all these prototypes that are 
> actually prototypes for @safe functions auto generated. You now get into 
> the habit of ignoring all @trusted prototypes as possible issues because 
> it's just noise. Better to focus on the @trusted implementations, which 
> is where the real problem can happen.
> ...

https://www.theregister.co.uk/2016/02/04/underhand_c_2015/


More information about the Digitalmars-d mailing list