From f055ad751246215a9760f6b053fd763470842b3a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 17 Dec 2018 23:18:00 +0100 Subject: [PATCH] Add a safety check to ARRAY_LENGTH Cause a compilation error on ARRAY_LENGTH(p) where p is a pointer as opposed to an array. This only works under GCC and compatible compilers such as Clang. On other compilers, ARRAY_LENGTH works but doesn't check the type of its argument. --- tests/suites/helpers.function | 36 +++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function index 38c16ad50..4a9d2a3bb 100644 --- a/tests/suites/helpers.function +++ b/tests/suites/helpers.function @@ -150,9 +150,41 @@ typedef struct data_tag mbedtls_exit( 1 ); \ } -/** Return the number of elements of a static or stack array. */ -#define ARRAY_LENGTH( array ) \ +#if defined(__GNUC__) +/* Test if arg and &(arg)[0] have the same type. This is true if arg is + * an array but not if it's a pointer. */ +#define IS_ARRAY_NOT_POINTER( arg ) \ + ( ! __builtin_types_compatible_p( __typeof__( arg ), \ + __typeof__( &( arg )[0] ) ) ) +#else +/* On platforms where we don't know how to implement this check, + * omit it. Oh well, a non-portable check is better than nothing. */ +#define IS_ARRAY_NOT_POINTER( arg ) 1 +#endif + +/* A compile-time constant with the value 0. If `const_expr` is not a + * compile-time constant with a nonzero value, cause a compile-time error. */ +#define STATIC_ASSERT_EXPR( const_expr ) \ + ( 0 && sizeof( struct { int STATIC_ASSERT : 1 - 2 * ! ( const_expr ); } ) ) +/* Return the scalar value `value` (possibly promoted). This is a compile-time + * constant if `value` is. `condition` must be a compile-time constant. + * If `condition` is false, arrange to cause a compile-time error. */ +#define STATIC_ASSERT_THEN_RETURN( condition, value ) \ + ( STATIC_ASSERT_EXPR( condition ) ? 0 : ( value ) ) + +#define ARRAY_LENGTH_UNSAFE( array ) \ ( sizeof( array ) / sizeof( *( array ) ) ) +/** Return the number of elements of a static or stack array. + * + * \param array A value of array (not pointer) type. + * + * \return The number of elements of the array. + */ +#define ARRAY_LENGTH( array ) \ + ( STATIC_ASSERT_THEN_RETURN( IS_ARRAY_NOT_POINTER( array ), \ + ARRAY_LENGTH_UNSAFE( array ) ) ) + + /* * 32-bit integer manipulation macros (big endian) */