Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Fri, 25 Sep 2020 16:10:02 +0200
From: Alejandro Colomar <colomar.6.4.3@...il.com>
To: libc-alpha@...rceware.org
Cc: libc-coord@...ts.openwall.com, libstdc++@....gnu.org, gcc@....gnu.org,
 linux-kernel@...r.kernel.org, linux-man@...r.kernel.org, fweimer@...hat.com,
 jwakely@...hat.com, ville.voutilainen@...il.com, enh@...gle.com,
 rusty@...tcorp.com.au
Subject: Re: [PATCH v2] <sys/param.h>: Add nitems() and snitems() macros



On 2020-09-25 15:20, Alejandro Colomar wrote:
 > 'nitems()' calculates the length of an array in number of items.
 > It is safe: if a pointer is passed to the macro (or function, in C++),
 > the compilation is broken due to:
 >   - In >= C11: _Static_assert()
 >   - In C89, C99: Negative anonymous bitfield
 >   - In C++: The template requires an array
 >
 > 'snitems()' is equivalent to nitems(),
 > but it returns a 'ptrdiff_t' instead of a 'size_t'.
 > It is useful for comparison with signed integer values.
 >
 > Some BSDs already provide a macro nitems() in <sys/param.h>,
 > although it usually doesn't provide safety against pointers.
 >
 > This patch uses the same name for compatibility reasons,
 > and to be the least disruptive with existing code.
 >
 > This patch also adds some other macros, which are required by 'nitems()':
 >
 > __is_same_type(_A, _B):
 > Returns non-zero if the two input arguments are of the same type.
 >
 > __is_array(_Arr):
 > Returns non-zero if the input argument is of an array type.
 >
 > __must_be(_Expr, _Msg):
 > Allows using _Static_assert() everywhere an expression can be used.
 > It evaluates '(int)0' or breaks the compilation.
 >
 > __must_be_array(_Arr):
 > It evaluates to '(int)0' if the argument is of an array type.
 > Else, it breaks compilation.
 >
 > __array_len(_Arr):
 > It implements the basic sizeof division needed to calculate the array 
length.
 >
 >
 > P.S.: I'd like to put this patch in the public domain.
 >
 >
 > Signed-off-by: Alejandro Colomar <colomar.6.4.3@...il.com>
 > ---

I patched my own system's <sys/param.h> with this,
and while 'nitems()' works fine,
I had to include <stddef.h> in my main.c to be able to use 'snitems()',
because I didn't have 'ptrdiff_t',
eventhough <sys/param.h> already includes <stddef.h>.

I completely ignore the mechanisms behind system headers including
other system headers.

Moreover, I didn't find 'ptrdiff_t' defined in any of my systems headers
I used 'user@...ian:/usr/include$ grep -rn ptrdiff_t'.  Does GCC do magic?

What's the problem with that?  How should I fix the patch?

My system:  Debian bullseye/sid; x86-64; gcc 10; libc 2.31-3

Thanks,

Alex


 >   misc/sys/param.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++
 >   1 file changed, 60 insertions(+)
 >
 > diff --git a/misc/sys/param.h b/misc/sys/param.h
 > index d7c319b157..88e95c2dba 100644
 > --- a/misc/sys/param.h
 > +++ b/misc/sys/param.h
 > @@ -102,5 +102,65 @@
 >   #define MIN(a,b) (((a)<(b))?(a):(b))
 >   #define MAX(a,b) (((a)>(b))?(a):(b))
 >
 > +/* Macros related to the types of variables */
 > +# define __is_same_type(_A, _B) 
__builtin_types_compatible_p(__typeof__(_A), \
 > + 
__typeof__(_B))
 > +# define __is_array(_Arr)	(!__is_same_type((_Arr), &(_Arr)[0]))
 > +
 > +/* Macros for embedding _Static_assert() in expressions */
 > +# if __STDC_VERSION__ >= 201112L
 > +#  define __must_be(_Expr, _Msg)  ( 
          \
 > +        0 * (int)sizeof( 
          \
 > +          struct { 
          \
 > +            _Static_assert((_Expr), _Msg); 
          \
 > +            char _ISO_C_forbids_a_struct_with_no_members; 
          \
 > +          } 
          \
 > +        ) 
          \
 > +)
 > +# else
 > +#  define __must_be(_Expr, _Msg)  ( 
          \
 > +        0 * (int)sizeof( 
          \
 > +          struct { 
          \
 > +            int  : (-!(_Expr)); 
          \
 > +            char _ISO_C_forbids_a_struct_with_no_members; 
          \
 > +          } 
          \
 > +        ) 
          \
 > +)
 > +# endif
 > +
 > +# define __must_be_array(_Arr)	__must_be(__is_array(_Arr), "Must be 
an array!")
 > +
 > +/* Macros for array sizes */
 > +#if defined(__cplusplus)
 > +# if __cplusplus >= 201103L
 > +template<typename _Tp, std::size_t _Len>
 > +  constexpr inline std::size_t
 > +  nitems(const _Tp(&)[_Len]) __THROW
 > +  {
 > +    return _Len;
 > +  }
 > +
 > +template<typename _Tp, std::size_t _Len>
 > +  constexpr inline std::ptrdiff_t
 > +  snitems(const _Tp(&)[_Len]) __THROW
 > +  {
 > +    return _Len;
 > +  }
 > +
 > +# else /* __cplusplus < 201103L */
 > +template<typename _Tp, std::size_t _Len>
 > +  char
 > +  (&__nitems_chararr(const _Tp(&)[_Len]))[_Len];
 > +
 > +#  define nitems(_Arr)          (sizeof(__nitems_chararr(_Arr)))
 > +#  define snitems(_Arr) 
(static_cast<std::ptrdiff_t>(nitems(_Arr)))
 > +# endif /* __cplusplus < 201103L */
 > +
 > +#else /* !defined(__cplusplus) */
 > +# define __array_len(_Arr)      (sizeof(_Arr) / sizeof((_Arr)[0]))
 > +# define nitems(_Arr)           (__array_len(_Arr) + 
__must_be_array(_Arr))
 > +# define snitems(_Arr)          ((ptrdiff_t)nitems(_Arr))
 > +#endif /* !defined(__cplusplus) */
 > +
 >
 >   #endif  /* sys/param.h */
 >

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.