Merge pull request #2104 from hanno-arm/iotssl-2071

Check that integer types don't use padding bits in selftest
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index c7bcc53..0c40686 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -49,7 +49,9 @@
 #include "mbedtls/ecjpake.h"
 #include "mbedtls/timing.h"
 #include "mbedtls/nist_kw.h"
+#include "mbedtls/debug.h"
 
+#include <limits.h>
 #include <string.h>
 
 #if defined(MBEDTLS_PLATFORM_C)
@@ -361,6 +363,78 @@
     }
 
     /*
+     * The C standard allows padding bits in the representation
+     * of standard integer types, but our code does currently not
+     * support them.
+     *
+     * Here we check that the underlying C implementation doesn't
+     * use padding bits, and fail cleanly if it does.
+     *
+     * The check works by casting the maximum value representable
+     * by a given integer type into the unpadded integer type of the
+     * same bit-width and checking that it agrees with the maximum value
+     * of that unpadded type. For example, for a 4-byte int,
+     * MAX_INT should be 0x7fffffff in int32_t. This assumes that
+     * CHAR_BIT == 8, which is checked in check_config.h.
+     *
+     * We assume that [u]intxx_t exist and that they don't
+     * have padding bits, as the standard requires.
+     */
+
+#define CHECK_PADDING_SIGNED(TYPE, NAME)                                \
+    do                                                                  \
+    {                                                                   \
+        if( sizeof( TYPE ) == 2 || sizeof( TYPE ) == 4 ||               \
+                sizeof( TYPE ) == 8 ) {                                 \
+            if( ( sizeof( TYPE ) == 2 &&                                \
+                (int16_t) NAME ## _MAX != 0x7FFF )             ||       \
+                ( sizeof( TYPE ) == 4 &&                                \
+                (int32_t) NAME ## _MAX != 0x7FFFFFFF )         ||       \
+                ( sizeof( TYPE ) == 8 &&                                \
+                (int64_t) NAME ## _MAX != 0x7FFFFFFFFFFFFFFF ) )        \
+            {                                                           \
+                mbedtls_printf( "Type '" #TYPE "' has padding bits\n" );\
+                mbedtls_exit( MBEDTLS_EXIT_FAILURE );                   \
+            }                                                           \
+        } else {                                                        \
+            mbedtls_printf( "Padding checks only implemented for types of size 2, 4 or 8" \
+                " - cannot check type '" #TYPE "' of size %" MBEDTLS_PRINTF_SIZET "\n",       \
+                sizeof( TYPE ) );                                       \
+            mbedtls_exit( MBEDTLS_EXIT_FAILURE );                       \
+        }                                                               \
+    } while( 0 )
+
+#define CHECK_PADDING_UNSIGNED(TYPE, NAME)                              \
+    do                                                                  \
+    {                                                                   \
+        if( ( sizeof( TYPE ) == 2 &&                                    \
+              (uint16_t) NAME ## _MAX != 0xFFFF )             ||        \
+            ( sizeof( TYPE ) == 4 &&                                    \
+              (uint32_t) NAME ## _MAX != 0xFFFFFFFF )         ||        \
+            ( sizeof( TYPE ) == 8 &&                                    \
+              (uint64_t) NAME ## _MAX != 0xFFFFFFFFFFFFFFFF ) )         \
+        {                                                               \
+            mbedtls_printf( "Type '" #TYPE "' has padding bits\n" );    \
+            mbedtls_exit( MBEDTLS_EXIT_FAILURE );                       \
+        }                                                               \
+    } while( 0 )
+
+    CHECK_PADDING_SIGNED( short,        SHRT );
+    CHECK_PADDING_SIGNED( int,           INT );
+    CHECK_PADDING_SIGNED( long,         LONG );
+    CHECK_PADDING_SIGNED( long long,   LLONG );
+    CHECK_PADDING_SIGNED( ptrdiff_t, PTRDIFF );
+
+    CHECK_PADDING_UNSIGNED( unsigned short,      USHRT );
+    CHECK_PADDING_UNSIGNED( unsigned,             UINT );
+    CHECK_PADDING_UNSIGNED( unsigned long,       ULONG );
+    CHECK_PADDING_UNSIGNED( unsigned long long, ULLONG );
+    CHECK_PADDING_UNSIGNED( size_t,               SIZE );
+
+#undef CHECK_PADDING_SIGNED
+#undef CHECK_PADDING_UNSIGNED
+
+    /*
      * Make sure we have a snprintf that correctly zero-terminates
      */
     if( run_test_snprintf() != 0 )