December 12, 2022
On Monday, 12 December 2022 at 06:13:20 UTC, youSureAboutThat wrote:
>
> // -release will disable runtime boundscheck for code annotated as @trusted and @system
> // however, code annotated with @safe will still have runtime boundscheck enabled.

further clarifying the above:

// -release will disable runtime boundscheck for code annotated as @trusted and @system
// and also code not annotated at all (as it defaults to @system)
// However, code annotated with @safe will still have runtime boundscheck enabled.

December 12, 2022

On Monday, 12 December 2022 at 03:48:26 UTC, Walter Bright wrote:

>

On 12/9/2022 2:39 PM, H. S. Teoh wrote:

>

According to dmd -h, they are disabled everywhere except @safe code.

Safe code is where bounds checking is needed.

>

And arguably, @system code is precisely where you WANT to have bounds
checks.

Use of @system code should be minimized and in it you're allowed to do whatever you want.

You have my 100% support here. But the tricky thing is that the majority of the current D language community seems to disagree with us, as evidenced by the apparent rejection of DIP 1028. And we should do a much better job convincing them to change their mind.

What kind of dangers are threatening the users of @system code? This needs to be explained better. Especially considering that every beginner pretty much starts using @system code by default even before knowing that there's a choice.

=== use after free ===

Right from the top of the Chromium list, the "use after free" security problem. Have a look at this forum thread. Presumably a beginner is asking about how to deal with a c-string returned by the sqlite3 library. And many of the forum regulars are very happily suggesting to use std.conv.fromStringz or some other ways of turning the pointer into a slice while avoiding a GC allocation. One person even believed that std.conv.fromStringz is doing a GC allocation. Now if this string is saved somewhere instead of just printing it, then we potentially have a "use after free" problem, because this memory is managed by sqlite3 and will get a realloc treatment by the follow-up sqlite3 API calls (I may be wrong, but that's what it looks like after quickly skimming through the sqlite3 source code). This is a potentially dangerous stuff and it mostly affects the @system code because the compiler remains silent about a lot of fishy things.

Also see the https://github.com/dlang/dmd/pull/14639 pull request. Some of the functions used to be incorrectly annotated as @trusted and this was fixed later.

The users (and especially beginners!) need to annotate their code as @safe before receiving any help from the compiler related to this problem.

=== references to stack variables escaping the scope ===

Here's a good example https://forum.dlang.org/post/duwrxnkjaafnzpfgnted@forum.dlang.org posted by someone, who is not a complete beginner (I can see their post https://forum.dlang.org/post/pdjvwvzysetndrtkxmea@forum.dlang.org from many months earlier). Looks like this person was not aware of the @safe attribute all this time. And possibly started experimenting and asking questions only after running into troubles and having to debug some real code.

Another interesting observation is that despite my recommendation to add "@safe:" at the top of the source file, this person still plastered the @safe attribute all over the place in the next code snippet. Also not recognizing this syntax doesn't seem uncommon: https://forum.dlang.org/post/ddhxlvprhdpqrhkbxuyb@forum.dlang.org

=== bounds checking ===

Bounds checking is not done in @safe and @trusted code in "-release" builds. How long does it typically take for a beginner to learn about this? And how many of them learn it proactively by reading the tutorials/documentation rather than getting surprised/ambushed by an unexpected segfault in their release build? This reminds me about https://forum.dlang.org/post/couzhdooeskwppuklasf@forum.dlang.org

Now let's look at the DUB ecosystem and what kind of options are used for compiling the existing DUB packages. Running dub build --help shows:

-b  --build=VALUE     Specifies the type of build to perform. Note that
                      setting the DFLAGS environment variable will override
                      the build type with custom flags.
                      Possible names:
                        debug, plain, release, release-debug,
                        release-nobounds, unittest, profile, profile-gc,
                        docs, ddox, cov, unittest-cov, syntax and custom
                        types

Trying these build types in verbose mode reveals that the following command line options are supplied to DMD:

debug            = "-debug -g -w ..."
plain            = "-w ..."
release          = "-release -inline -O -w ..."
release-debug    = "-release -g -inline -O -w ..."
release-nobounds = "-release -inline -noboundscheck -O -w ..."

Basically -O is always bundled together with -release and DUB packages built with optimizations won't have bounds checking in @system code. Of course, unless the packages explicitly override this in their sdl/json.

So we are in a rather weird situation. At least in the DUB ecosystem a lot of applications and libraries de-facto may have unnecessary security issues caused by having too much @system code. The community doesn't want to change the default from @system to @safe. And at the same time the same community wants to promote D as a safe language. People do get upset when, let's say, NSA is not listing D as an example of a safe language.

=== how to fix all of this ===

My suggestion is still the same: the compiler should start making noise whenever a function gets the @system attribute assigned to it by default. Similar to deprecation warnings. This message does not have to abort compilation and the existing DUB packages should still build successfully (despite the '-w' option). The text of the message may look like this:

"The function 'foobar' got @system attribute by default. If this is really what you want, then please add '@system:' at the top of the source file or read this <URL> for detailed explanations."

I think that this will provide a gentle push/reminder for the maintainers of the existing packages. Also beginners will learn about the @safe attribute much faster.

December 12, 2022
On Monday, 12 December 2022 at 06:13:20 UTC, youSureAboutThat wrote:
> On Monday, 12 December 2022 at 05:06:06 UTC, youSureAboutThat wrote:
>>
>
> just to clarify -> when @safe isn't safe:
>
>
> module test;
>
> import std.stdio;
>
> // so -boundscheck=off will always disable runtime boundscheck,
> // regardless of whether code is annotated as @safe, @system, or @trusted.
>
> // -release will disable runtime boundscheck for code annotated as @trusted and @system
> // however, code annotated with @safe will still have runtime boundscheck enabled.
>
> // here is where it's a little tricky...
> // calling code annotated with @trusted from code annotated with @safe (see below).
>
> @safe void main() { foo(); } // even though this is marked as @safe
>                              // when you compile with -release
>                              // boundscheck is disabled for foo()
>                              // since foo() is marked as @trusted
>                              // and -release removes boundscheck
>                              // for @trusted and @system..(but not @safe)
>
> @trusted foo()
> {
>     int[5] array = [0, 1, 2, 3, 4];
>
>     for (size_t i = 0; i < array.length + 1; i++)
>         writeln("Element ", i, " = ", array[i]);
> }

You're supposed to catch this bug during development and with your tests but here the real problem is "-release" (that problem's been mentioned earlier).

That switch is not well designed. Bound checks could have their own front-end optimizations so we could have

    -boundscheck={on|optimized|off}

instead of the current system, tied to the language safety system.
December 12, 2022
On Monday, 12 December 2022 at 06:23:09 UTC, youSureAboutThat wrote:
>
> further clarifying the above:
>
> // -release will disable runtime boundscheck for code annotated as @trusted and @system

Unless you override the default bounds checks option.

> // and also code not annotated at all (as it defaults to @system)

Except certain functions can be inferred as safe:
https://dlang.org/spec/function.html#function-attribute-inference



December 12, 2022
On Monday, 12 December 2022 at 11:21:29 UTC, Basile B. wrote:
> On Monday, 12 December 2022 at 06:13:20 UTC, youSureAboutThat wrote:
>> [...]
>
> You're supposed to catch this bug during development and with your tests but here the real problem is "-release" (that problem's been mentioned earlier).
>
> That switch is not well designed. Bound checks could have their own front-end optimizations so we could have
>
>     -boundscheck={on|optimized|off}
>
> instead of the current system, tied to the language safety system.

to extend the idea. The problem would be then that there's no way to disable assertions, so we also need

    -assertion={on|off}

And then we can drop -release. Actually release is more like a set of switches that's not always ideal. It would be better to have the oppostunity to control each single particular code instrumentation.
December 12, 2022

On Monday, 12 December 2022 at 11:21:29 UTC, Basile B. wrote:

> >

@trusted foo()
{
int[5] array = [0, 1, 2, 3, 4];

for (size_t i = 0; i < array.length + 1; i++)
    writeln("Element ", i, " = ", array[i]);

}

You're supposed to catch this bug during development and with your tests

The amount of @trusted and @system code is supposed to be relatively small in any application (this is possible thanks to the Pareto principle), so it can be reviewed with extra scrutiny and carefully tested. And this code is the primary suspect when troubleshooting in case of troubles.

Testing and reviewing efforts can be allocated more efficiently when @safe and @trusted/@system code is segregated.

>

but here the real problem is "-release" (that problem's been mentioned earlier).

The real problem is not "-release". But the fact that way too much code gets annotated as @system for no reason. And for beginners even effectively without their intention/consent.

>

That switch is not well designed. Bound checks could have their own front-end optimizations so we could have

-boundscheck={on|optimized|off}

Such switch already exists. And I'm using it during development for very narrow specific purposes:

  1. To do a test build with "-boundscheck=off" and run benchmarks. If the performance difference is not measurable, then everything is fine. If there's some difference, then identify the part of code responsible for it and consider the risks/benefits of changing specifically this part to @trusted/@system.

  2. When debugging, "-boundscheck=on" for everything may assist in catching an unexpected bug in @trusted/@system code.

>

instead of the current system, tied to the language safety system.

Why instead? The two extreme options ("full checks everywhere" vs. "no checks at all") offered by the command line switches are not flexible and both have major disadvantages.

December 12, 2022
On Monday, 12 December 2022 at 12:23:08 UTC, Basile B. wrote:
> On Monday, 12 December 2022 at 11:21:29 UTC, Basile B. wrote:
>> On Monday, 12 December 2022 at 06:13:20 UTC, youSureAboutThat wrote:
>>> [...]
>>
>> You're supposed to catch this bug during development and with your tests but here the real problem is "-release" (that problem's been mentioned earlier).
>>
>> That switch is not well designed. Bound checks could have their own front-end optimizations so we could have
>>
>>     -boundscheck={on|optimized|off}
>>
>> instead of the current system, tied to the language safety system.
>
> to extend the idea. The problem would be then that there's no way to disable assertions, so we also need
>
>     -assertion={on|off}
>
> And then we can drop -release. Actually release is more like a set of switches that's not always ideal. It would be better to have the oppostunity to control each single particular code instrumentation.

well TIL we have

    -check=[assert|bounds|in|invariant|out|switch][=[on|off]]

so why bother why -release at all ?
You can control finely each instrumentation already 😁😁


December 12, 2022

On Monday, 12 December 2022 at 11:07:00 UTC, Siarhei Siamashka wrote:

>

You have my 100% support here. But the tricky thing is that the majority of the current D language community seems to disagree with us, as evidenced by the apparent rejection of DIP 1028.

That was unpopular because extern(C) functions silently defaulted to @trusted, a major security hole. However I am concerned about breakage if the default changes, and the lack of a @trusted block. The latter means you can't encapsulate @trusted code easily if it contains a return statement because you have to wrap it in a lambda (which repurposes that return). It could be abused, but we need to give programmers practical tools and not make things unnecessarily difficult and noisy. Rust has unsafe blocks.

>

What kind of dangers are threatening the users of @system code? This needs to be explained better. Especially considering that every beginner pretty much starts using @system code by default even before knowing that there's a choice.

What about deprecating defining main without a @system/@trusted/@safe attribute? Then users have to make a choice. If they choose @safe then anything main calls has to have a safe interface.

>

Another interesting observation is that despite my recommendation to add "@safe:" at the top of the source file, this person still plastered the @safe attribute all over the place in the next code snippet. Also not recognizing this syntax doesn't seem uncommon: https://forum.dlang.org/post/ddhxlvprhdpqrhkbxuyb@forum.dlang.org

I almost never use @safe: because it prevents @safe attribute inference.

>

And at the same time the same community wants to promote D as a safe language. People do get upset when, let's say, NSA is not listing D as an example of a safe language.

Even if D was safe by default, would the NSA really list it? They seem to only list some examples of better-known languages:

"Examples of memory safe language include C#, Go, Java®, Ruby™, Rust®, and Swift®."
https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI_SOFTWARE_MEMORY_SAFETY.PDF

Of course, if D can encourage/default to using @safe that may make the language more popular by helping market it.

>

=== how to fix all of this ===

My suggestion is still the same: the compiler should start making noise whenever a function gets the @system attribute assigned to it by default. Similar to deprecation warnings. This message does not have to abort compilation and the existing DUB packages should still build successfully (despite the '-w' option). The text of the message may look like this:

"The function 'foobar' got @system attribute by default. If this is really what you want, then please add '@system:' at the top of the source file or read this <URL> for detailed explanations."

I think that this will provide a gentle push/reminder for the maintainers of the existing packages. Also beginners will learn about the @safe attribute much faster.

Sounds more appropriate for a linter.

December 12, 2022

On Monday, 12 December 2022 at 11:07:00 UTC, Siarhei Siamashka wrote:

>

Bounds checking is not done in @safe and @trusted code in "-release" builds.

False. Compile this with -release:

@safe int main()
{
	auto a = [1];
	return a[1];
}

core.exception.ArrayIndexError@safestd.d(4): index [1] is out of bounds for array of length 1

??:? _d_arraybounds_indexp [0x561bc98fb805]
??:? _Dmain [0x561bc98fb75d]

December 12, 2022

On Monday, 12 December 2022 at 12:57:54 UTC, Nick Treleaven wrote:

>

On Monday, 12 December 2022 at 11:07:00 UTC, Siarhei Siamashka wrote:

>

Bounds checking is not done in @safe and @trusted code in "-release" builds.

False. Compile this with -release:

Is it really difficult to see that this was a typo given the context? You need to read it as @system and @trusted code.