From: Martin Uecker <uecker@tugraz.at>
To: Linus Torvalds <torvalds@linux-foundation.org>, paulmck@kernel.org
Cc: linux-toolchains@vger.kernel.org, peterz@infradead.org,
hpa@zytor.com, rostedt@goodmis.org, gregkh@linuxfoundation.org,
keescook@chromium.org
Subject: Re: A few proposals from the C standards committee
Date: Tue, 23 Jan 2024 23:35:42 +0100 [thread overview]
Message-ID: <75523ebad311c04d3af0a786c458ea7a9c63c725.camel@tugraz.at> (raw)
In-Reply-To: <CAHk-=whQVv2T7+888Y-rR5gBhtoQJGHjZ2TAg+E7_JU29VVm1g@mail.gmail.com>
Am Dienstag, dem 23.01.2024 um 10:58 -0800 schrieb Linus Torvalds:
> I generally like them, but..
>
> On Tue, 23 Jan 2024 at 08:46, Paul E. McKenney <paulmck@kernel.org> wrote:
> >
> > N3089 _Optional: a type qualifier to indicate pointer nullability
> > Proposes _Optional to tag pointer parameters such that
> > dereferencing the pointer without first checking for NULL gets
> > a compiler warning.
> > https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3089.pdf
>
> This one I also like, but at the same time I'm not convinced "types"
> are the right way to carry this information.
>
> Because types are historically conceptually static and tied to the
> lifetime of the object.
>
> But the actual nullability logic must *not* be.
>
> _Nonnull is fine: if a variable is non-null, it can conceptually never
> become anything else (or rather: it would remain a bug if it did).
>
> So _Nonnull is a "statement of fact" about the variable, and makes
> sense as a type, and matches the lifetime of the variable.
>
> But the same is *not* true of _Nullable. The type magically and
> silently changes after a test.
The interesting thing about _Optional is that it is not qualifier
on the pointer but a qualifier on the target. So conversion
from _Optional to a regular pointer would give you the diagnostic
via the usual rules for pointer conversion. The paper then
suggests &*ptr as syntax to transform the pointer with qualifier
into a pointer without qualifier (after a check). Not sure
the design is perfect, but it seems better than _Nonnull and
_Nullable.
Martin
>
> To make a trivial stupid example of what I mean, something like
>
> inline int access(int * _Nonnull p) { return *p; }
> ...
> int my_fn(int * _Nullable p)
> { return p ? access(p) : 0; }
>
> which is obviously correct, and shouldn't warn for anything, since
> this is literally what the whole thing is designed for.
>
> But part of that "shouldn't warn" is how a nullable 'p' is effectively
> silently cast to a non-nullable 'p'. The only thing that makes that
> cast valid is the presence of the conditional, but it should be noted
> that from a *type* perspective that is just wrong.
>
> IOW, normal types are carried along with their variables, but somehow
> the variable 'p' inside the conditional is not really of the the same
> type as 'p' outside of it.
>
> So that conditional has that hidden effect of changing what the type
> of 'p' is in all dependent expressions.
>
> And I know compilers already effectively implement all this, but I'm
> just saying that from a *type* system standpoint, this is all quite a
> bit illogical.
>
> In many ways, this is not a type issue, it's really a "value range
> analysis" issue. And I think it should be considered that waym, and
> the syntax and the logic be also talked about in those terms.
>
> Why would "_Nullable" and "_Nonnull" be conceptually any different
> from "I know this value is in the range [0..5]", which is *also*
> something that compilers already do, and that we also might want to be
> able to describe for warning purposes?
>
> So honestly, I would *love* to be able to give the compiler range
> information (which *includes* the "this is nullable" kind of
> information), but I don't think it should be described as a "type
> qualifier".
>
> Because what if the nullability is hidden in some called function?
> Tove give another example - less stuipid this time - think of
> somethign like this:
>
> int my_fn(int * _Nullable p)
> {
> if (check_validity(p))
> return -EINVAL;
> return access(p);
> }
>
> where we have perhaps done extensive validity checks on 'p' (think the
> kernel kind of 'access_ok()' function) in the 'check_validity()'
> function, but the compiler doesn't see that function, since it's a
> rather complicated one that does a whole RB-tree lookup etc. So the
> compiler hasn't *seen* that we do a NULL check there.
>
> So it shouldn't warn, but it will - because the compiler is oblivious
> about the fact that the pointer has actually been checked for a lot
> more than just NULL.
>
> If you think of this as a "value analysis" issue, rather than as a
> type issue, the solution is obvious: it's not that the type of 'p'
> changes, but you just want a way to tell the compiler "I've done range
> checking, the new range is XYZ".
>
> And if you think of it that way, you don't want to re-decare a type,
> you want to just update range information, and simply state something
> like like
>
> _Nonnull p;
>
> after doing the check_validity() call. IOW, I really think you should
> be able to write something like
>
> int my_fn(int * _Nullable p)
> {
> if (check_validity(p))
> return -EINVAL;
> _Nonnull p;
> return access(p);
> }
>
> See? My argument is basically that I like the _Nullable/_Nonnull
> attributes, but that they shouldn't be seen as part of the *type*
> system, but as a more dynamic value range thing, and that they can -
> and should - be available separately from just the declaration.
>
> Linus
next prev parent reply other threads:[~2024-01-23 22:45 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-23 16:46 A few proposals from the C standards committee Paul E. McKenney
2024-01-23 18:58 ` Linus Torvalds
2024-01-23 20:00 ` Paul E. McKenney
2024-01-23 20:20 ` Linus Torvalds
2024-01-23 20:35 ` Jakub Jelinek
2024-01-23 20:43 ` Linus Torvalds
2024-01-23 20:46 ` H. Peter Anvin
2024-01-24 13:46 ` Paul E. McKenney
2024-01-25 13:00 ` Paul E. McKenney
2024-01-24 13:16 ` Paul E. McKenney
2024-01-23 20:44 ` H. Peter Anvin
2024-01-24 12:52 ` Paul E. McKenney
2024-01-23 20:39 ` Linus Torvalds
2024-01-23 22:35 ` Martin Uecker [this message]
2024-01-23 20:16 ` H. Peter Anvin
2024-01-23 20:24 ` Linus Torvalds
2024-01-24 14:58 ` Paul E. McKenney
2024-01-25 12:52 ` Paul E. McKenney
2024-01-23 22:39 ` Kees Cook
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=75523ebad311c04d3af0a786c458ea7a9c63c725.camel@tugraz.at \
--to=uecker@tugraz.at \
--cc=gregkh@linuxfoundation.org \
--cc=hpa@zytor.com \
--cc=keescook@chromium.org \
--cc=linux-toolchains@vger.kernel.org \
--cc=paulmck@kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).