[cfe-dev] ISO C3X proposal: nonnull qualifier

Alejandro Colomar (man-pages) via cfe-dev cfe-dev at lists.llvm.org
Mon Nov 15 08:01:49 PST 2021


Hi all,

I'd like to propose the following feature for ISO C (and also ISO C++).
It is based on a mix of GCC's [[gnu::nonnull]] and Clang's _Nonnull,
with a pinch of salt of mine.

I'd like to get some feedback from GCC and Clang,
before sending it as an official proposal.

BTW, since the working group is probably very busy with C2X,
I may delay sending it more than a year.
Or I may propose it first to ISO C++,
and then to ISO C.

I wrote the initial draft in the form of a manual page,
whose source code can be found here:
<https://github.com/alejandro-colomar/nonnull>

It has a Makefile to easily transform it into a PDF.
I also rendered it with cat to inline it in this email.


Cheers,
Alex


---
nonnull(3)                    Nxxxx                   nonnull(3)

NAME
       nonnull - non‐null pointer

SYNOPSIS
       type‐qualifier:
            const
            nonnull
            restrict
            volatile
            _Atomic

DESCRIPTION
   Constraints
       Types   other   than   pointer   types   shall   not   be
       nonnull‐qualified.

   Semantics
       The properties associated with qualified types are  mean‐
       ingfull only for expressions that are lvalues.

       If  the same qualifier appears more than once in the same
       specifier‐qualifier list or  as  declaration  specifiers,
       either directly or via one or more typedefs, the behavior
       is the same as if it appeared only once.  If other quali‐
       fiers  appear  along  with the _Atomic qualifier, the re‐
       sulting type is the so‐qualified atomic type.

       If an attempt is made to assign NULL to a pointer defined
       with  the  nonnull  qualifier, the behavior is undefined.
       If an attempt is made to refer to a pointer with a  non‐‐
       nonnull‐qualified  type through the use of an lvalue with
       nonnull‐qualified type, the behavior is undefined.

       The intended use of the nonnull and  restrict  qualifiers
       (like the register storage class) is to promote optimiza‐
       tion, and deleting all instances of  the  qualifier  from
       all  preprocessing translation units composing a conform‐
       ing program does not change its meaning (i.e., observable
       behavior).

NOTES
       These  rules  for  nonnull are somewhat of the reverse of
       const: Instead of forbidding the discarding of the quali‐
       fier,  we forbid the addition of the qualifier.  The rea‐
       son is that constant variables are a subset of variables,
       and  the  danger  is  in  treating a const as a variable.
       Similarly, nonnull pointers are a  subset  of  (possibly‐
       NULL)  pointers,  but the danger is in treating possibly‐
       NULL pointers as nonnull pointers.

   Prior art
       GCC has [[gnu::nonnull]].  Why is this better?

       It can be applied more specifically in the case of point‐
       ers  to pointers.  And, like with const, the nonnull‐ness
       can be better enforced by passing the qualifier around.

       However,  we  recognize  the  optimizations  allowed   by
       [[gnu::nonnull]],  and also allow them, by specifying the
       behavior as undefined when the qualifier is  misused,  as
       GCC does.

       Clang has _Nonnull.  Why is this better?

       Clang found that using a qualifier was better than an at‐
       tribute, since it allowed to more specifically  apply  it
       to pointers to pointers.  We recognize that, and also use
       a qualifier.

       Clang doesn't specify the behavior  as  being  undefined.
       That  forbids optimizations, that would otherwise be pos‐
       sible.  We prefer to allow for those optimizations.

       Clang considers this qualifier to be useful only as a di‐
       agnostics  generator.   We not only allow for diagnostics
       to be issued, but we have stricter  rules  that  make  it
       more difficult to produce incorrect code.

       Even  though the language has reserved identifiers start‐
       ing with underscore + uppercase for  this  kind  of  key‐
       words,  Clang has already used _Nonnull, and since we are
       changing the meaning, it might cause problems to existing
       code.  So nonnull seems a better name, which hopefully is
       not used by existing code, or at least it is less used.

EXAMPLES
   Correct
       strcpy(3) may be implemented in  the  following  way,  to
       signify that it cannot accept NULL as input to any of its
       arguments, and that it cannot ever return NULL either.

       char *nonnull strcpy(char *nonnull restrict dest,
                            const char *nonnull restrict src)
       {
            char *d;

            d = dest;
            while ((*d++ = *src++) != '\0');

            return dest;
       }

       Note that d need not be nonnull‐qualified, since possibly
       being NULL is a superset of not possibly being NULL.

       The  following variations of the above are incorrect, for
       the reasons that follow the code examples.

   Incorrect
       char *strcpy(char *nonnull restrict dest,
                    const char *nonnull restrict src)
       {
            char *d;

            d = dest;
            while ((*d++ = *src++) != '\0');

            return dest;
       }

       Although this would be valid by itself (wouldn't have un‐
       defined  behavior),  it  forbids  callers of the function
       from assigning the return value  to  a  nonnull‐qualified
       pointer.

   Undefined behavior
       char *nonnull strcpy(char *restrict dest,
                            const char *nonnull restrict src)
       {
            char *d;

            d = dest;
            while ((*d++ = *src++) != '\0');

            return dest;
       }
       This  causes undefined behavior, since it assigns a non‐‐
       nonnull‐qualified pointer (dest) to a qualified one  (the
       return value).  It's also dangerous, since the user isn't
       properly informed that NULL may cause undefined  behavior
       in  the  implementation of the function (dest is derefer‐
       enced).

AUTHORS
       Alejandro Colomar

       I must thank the GCC and  Clang  programmers  for  having
       provided a solid base on which I based this proposal.

SEE ALSO
       N2731 ‐ 6.7.3

       ⟨https://gcc.gnu.org/onlinedocs/gcc/Common‐Function‐
       Attributes.html#Common‐Function‐Attributes⟩

       ⟨https://clang.llvm.org/docs/AttributeReference.html
       #nullability‐attributes⟩

C3X                        2021‐11‐15                 nonnull(3)



-- 
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/


More information about the cfe-dev mailing list