April 16

On Wednesday, 16 April 2025 at 22:43:24 UTC, Derek Fawcus wrote:

>
$ clang-14 -Wall -Wnullable-to-nonnull-conversion -c ttt.c
ttt.c:37:8: warning: implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull' [-Wnullable-to-nonnull-conversion]
        ptr = arg3;
              ^
ttt.c:41:20: warning: implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull' [-Wnullable-to-nonnull-conversion]
        a += *someNonNull(arg3);
                          ^
ttt.c:29:16: warning: variable 'ptr' set but not used [-Wunused-but-set-variable]
        int * NONNULL ptr;
                      ^
3 warnings generated.

Having now got this to complain in the desired fashion, I'll now be applying it to some code at work. More help in quashing sources of bugs.

April 17
On 17/04/2025 10:50 AM, Derek Fawcus wrote:
> On Wednesday, 16 April 2025 at 21:12:08 UTC, Walter Bright wrote:
>> I'm curious - how does one traverse a binary tree with non-null pointers? How does one create a circular data structure with non-null pointers?
> 
> One has nullable and nonnull pointers.  One uses the former for the circular data structures.
> 
> Now the current ugly bit with clang is this:
> 
> ```C
> int foo(int * arg1, int * NULL_UNSPECIFIED arg2, int * NULLABLE arg3) {
> 
>          if (arg3 != 0)
>                  ptr = arg3;
> 
>          return a;
> }
> ```
> 
> ```
> $ clang-14 -Wall -Wnullable-to-nonnull-conversion -c ttt.c
> ttt.c:36:9: warning: implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull' [-Wnullable-to- nonnull-conversion]
>                  ptr = arg3;
>                        ^
> ```
> 
> i.e. there is no DFA, and one still has to cast the value in the assignment.  So the clang support could stand some improvement.

I've been implementing this specific thing in my fast DFA implementation recently.

Truthiness is needed for it to work.

However you can still be using DFA without supporting truthiness of variables.

DFA is a very large subject domain.

April 16

On Wednesday, 16 April 2025 at 19:44:09 UTC, Walter Bright wrote:

>

On 4/16/2025 11:43 AM, Derek Fawcus wrote:

>

However I do have an interest in being able to write code with distinct nullable and nonnull pointers.  That such that the compiler (or an SA tool) can complain when they're incorrectly confused.

That's what templates are for!

I can't say I've played with them much, having come from C not C++.

I see there is the ability to overload the unary '*' operator, and so can imagine how one could define a struct providing a non-null form of pointer.

But just how awkward is that going to be for mixed forms of nullability in function definitions. Without trying, i suspect it will just get too awkward.

e.g., how would the equivalent of this args end up in a D rendition:

int foo(char * _Nonnull * _Nullable a, int * _Nullable * _Nonnull b);
April 17
On 17/04/2025 10:54 AM, Derek Fawcus wrote:
> On Wednesday, 16 April 2025 at 22:43:24 UTC, Derek Fawcus wrote:
>> ```
>> $ clang-14 -Wall -Wnullable-to-nonnull-conversion -c ttt.c
>> ttt.c:37:8: warning: implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull' [-Wnullable- to-nonnull-conversion]
>>         ptr = arg3;
>>               ^
>> ttt.c:41:20: warning: implicit conversion from nullable pointer 'int * _Nullable' to non-nullable pointer type 'int * _Nonnull' [-Wnullable- to-nonnull-conversion]
>>         a += *someNonNull(arg3);
>>                           ^
>> ttt.c:29:16: warning: variable 'ptr' set but not used [-Wunused-but- set-variable]
>>         int * NONNULL ptr;
>>                       ^
>> 3 warnings generated.
>> ```
> 
> Having now got this to complain in the desired fashion, I'll now be applying it to some code at work.  More help in quashing sources of bugs.

After a quick play, I would suggest also passing ``--analyze`` if you are not already doing so.

It covers the case where you are not assuming non-null.

I.e. it can see the difference between:

```c++
void test(int *p) {
  if (!p)
    *p = 0; // warn
}
```

and

```c++
void test2(int *p) {
  if (p)
    *p = 0; // ok
}
```

This is definitely DFA.


April 17
On 17/04/2025 11:08 AM, Derek Fawcus wrote:
> On Wednesday, 16 April 2025 at 19:44:09 UTC, Walter Bright wrote:
>> On 4/16/2025 11:43 AM, Derek Fawcus wrote:
>>> However I do have an interest in being able to write code with distinct nullable and nonnull pointers.  That such that the compiler (or an SA tool) can complain when they're incorrectly confused.
>>
>> That's what templates are for!
> 
> I can't say I've played with them much, having come from C not C++.
> 
> I see there is the ability to overload the unary '*' operator, and so can imagine how one could define a struct providing a non-null form of pointer.
> 
> But just how awkward is that going to be for mixed forms of nullability in function definitions.  Without trying, i suspect it will just get too awkward.
> 
> e.g., how would the equivalent of this args end up in a D rendition:
> 
> ```C
> int foo(char * _Nonnull * _Nullable a, int * _Nullable * _Nonnull b);
> ```

The current C++ analyzer for clang doesn't support that.

```c++
int foo(char ** _Nullable a, int ** _Nonnull b);
```

Would be more accurate.

For D, my design work for type state analysis would have it be:

```d
int foo(/*?initialized*/ char** a, ?nonnull int** b);
```

If you want to dereference twice, you need to perform a load + check.

```d
if (auto c = *b) {
	int d = *c;
}
```

Some syntax sugar can lower to that.

April 16
Sounds like one must do a bunch of casting to make use of non-nullable pointers?
April 16
```C
int foo(int * arg1, int * NULL_UNSPECIFIED arg2, int * NULLABLE arg3) {
```

https://www.youtube.com/watch?v=vEr0EAcSWcc

April 16
On 4/16/2025 2:49 PM, Dave P. wrote:
> Where the annotations are really valuable is for function arguments and return. Can this argument be null or not? Now the compiler can help you instead of you having to memorize the documentation of every function you call.

I've long since given up on memorizing the documentation of each parameter. Too many functions! I just google it, it just takes a sec.


> I’ve consistently applied these annotations to my C projects and it works wonders. Many classes of mistakes are caught at compile time.

I agree that compile time detection is always better than runtime.

I get a null pointer seg fault now and then. I look at the stack trace, and have it fixed in the same amount of time it takes you.

I don't worry about it, because it is not a memory corruption issue.

The time I spend tracking down a null pointer seg fault does not even register among the time I spend programming.

You're not wrong. But it's a cost/benefit thing.

> Somethings are a
> dynamic property of your system, and for that there is a nullability sanitizer
> that can detect at runtime if a `_Nonnull` pointer gets a null value (usually
> from a data structure that was not properly initialized).

I don't see how a runtime detector can work better than a seg fault with stack trace.

April 16
On 4/16/2025 4:08 PM, Derek Fawcus wrote:
> e.g., how would the equivalent of this args end up in a D rendition:
> 
> ```C
> int foo(char * _Nonnull * _Nullable a, int * _Nullable * _Nonnull b);
> ```

```d
int foo(_Nullable!(_Nonnull!char)) a, _Nonnull!(_Nullable!int) b);
```
April 17

On Thursday, 17 April 2025 at 05:31:48 UTC, Walter Bright wrote:

>

On 4/16/2025 2:49 PM, Dave P. wrote:

>

[...]
I've long since given up on memorizing the documentation of each parameter. Too many functions! I just google it, it just takes a sec.

It’s easier to goto-definition and see the annotations. Fancier editors can even show it inline.

>

[...]
I don't see how a runtime detector can work better than a seg fault with stack trace.

The source of a null pointer can be very far from its eventual dereference, especially when stored in a structure.

The nullability sanitizer also doesn’t kill your program by default, it just logs when a null pointer is stored in a nonnull variable. So you can see where the first non null store is made and see how it eventually moves to when it is derefenced.


It’s funny though, when I first started using this kind of thing it caught loads of bugs. But after years of use, I realized it hadn’t caught any bugs in a long time. I had internalized the rules.