Memory safe in D

Nick Treleaven nick at geany.org
Fri Mar 22 10:51:41 UTC 2024


On Monday, 18 March 2024 at 22:46:27 UTC, Walter Bright wrote:
> Some easy cases can be handled easily(!). But to do it 
> reliably, DFA is required. And DFA makes the front end slow.
>
> If one doesn't do DFA, then I will be subjected to endless bug 
> reports where people find a case that needs DFA to resolve.

Sorry my reply wasn't rigorous enough.

>>    if (i) a = new A();
>
> If `a` is non-nullable, this line could be made to error 
> because there is no `else` branch that also initializes `a`. 
> This is what cppfront does.

I think this is workable without DFA, the compiler just tracks 
when a variable is initialized. There is never a state where a 
variable may be both initialized and not initialized (e.g. no 
dependency on whether a jump instruction was taken at runtime). 
Do you think this is reasonably cheap time cost?

>>    if (i) a.bar();
>
> If `a` is nullable, this line is an error because you are 
> calling a method that needs an A when (from the DFA-less 
> compiler's point of view) you might only have a null pointer.
>
> To handle that, you either:
> * `assert(a)` before `a.bar()`, and the compiler assumes `a` is 
> not null and in release mode there is only a hardware null 
> check.

This alone indeed does not work in general as `a` may become null 
after the assert and before it is dereferenced.

> * Call a function to force-unwrap the nullable type to a 
> non-null type, e.g. `a.unwrap.bar()`. This function can be a 
> no-op in terms of hardware, but requiring calling it makes the 
> programmer aware that a possible null dereference (at least 
> from the compiler POV) may occur.

This works and requires no analysis. The function internally just 
casts to non-null, the advantage being that the call is explicit 
to the programmer, alerting them and reviewers to possible 
program abort.

This alone might be workable in theory but in practice it would 
probably be annoying in some cases where the compiler could help.

> * Rewrite the if statement to `if (a)`. That is actually better 
> code because you would need to check that `i` hadn't changed in 
> between the two if statements, which might be long, to 
> understand the code.

Like assert, this is not workable in the general case. However, 
declaring a new variable could work:

```d
if (auto b = a) {
     b.bar;
}
```
There are 2 options:
1. The type of `b` is non-nullable. This is a breaking change. 
There would need to be some syntax for opting in to make `b` 
nullable.
2. We have some other syntax for `b` being non-nullable.

Workable?


More information about the Digitalmars-d mailing list