LCOV - code coverage report
Current view: directory - src/include - nacl_macros.h (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 4 3 75.0 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : 
       8                 : /*
       9                 :  * NaCl Safety Macro Definitions
      10                 :  */
      11                 : #ifndef NATIVE_CLIENT_SRC_INCLUDE_NACL_MACROS_H_
      12                 : #define NATIVE_CLIENT_SRC_INCLUDE_NACL_MACROS_H_ 1
      13                 : 
      14                 : #include <stdio.h>
      15                 : #include <stdlib.h>
      16                 : 
      17                 : /*****************************************************************************
      18                 :  * Safety macros                                                             *
      19                 :  *****************************************************************************/
      20                 : 
      21                 : #define NACL_ARRAY_SIZE_UNSAFE(arr) ((sizeof arr)/sizeof arr[0])
      22                 : 
      23                 : /*
      24                 :  * ASSERT_IS_ARRAY(arr) generates a somewhat opaque compile-time
      25                 :  * error if arr is a non-array pointer.  This protects against
      26                 :  * situations where one writes code like:
      27                 :  *
      28                 :  * foo.h:  struct Foo { char buffer[BUFFERSIZE]; size_t sofar; ... };
      29                 :  *
      30                 :  * foo.c:  got = read(d, fp->buffer + fp->sofar, sizeof fp->buffer - fp->sofar);
      31                 :  *         if (-1 == got) { ... }
      32                 :  *         fp->sofar += got;
      33                 :  *
      34                 :  *         for (ix = 0; ix < sizeof arr/sizeof arr[0]; ++ix) { ... }
      35                 :  *
      36                 :  * and have it break and create a security problem when somebody later
      37                 :  * changes Foo to dynamically allocate buffer, viz,
      38                 :  *
      39                 :  * foo.h:  struct Foo { char *buffer; size_t sofar; ... };
      40                 :  *
      41                 :  * and now sizeof fp->buffer is 4 or 8, with size_t (type of sizeof)
      42                 :  * being unsigned, when fp->sofar is larger than 4 or 8, getting an
      43                 :  * enormous maximum read size being used.  Such bugs can remain
      44                 :  * undiscovered when conforming implementations of protocol engines
      45                 :  * are used where the actual amount sent is small and would never
      46                 :  * cause a buffer overflow, but an adversarial implementation would be
      47                 :  * able to clobber the heap.  The solution is to write:
      48                 :  *
      49                 :  * foo.c:  NACL_ASSERT_IS_ARRAY(fp->buffer);
      50                 :  *         got = read(d, fp->buffer + fp->sofar, sizeof fp->buffer - fp->sofar);
      51                 :  *         if (-1 == got) { ... }
      52                 :  *         fp->sofar += got;
      53                 :  *
      54                 :  *         for (ix = 0; ix < NACL_ARRAY_SIZE(arr); ++ix) { ... }
      55                 :  *
      56                 :  * and when foo.h is modified, it will generate a compile-time error
      57                 :  * alerting the engineer makin the change that the read code will need to
      58                 :  * be modified.
      59                 :  *
      60                 :  * NB: The -pedantic flag is REQUIRED for the C version to catch the
      61                 :  *     error.  No special warning flags are required for the C++
      62                 :  *     version to work.
      63                 :  */
      64                 : 
      65                 : #ifdef __cplusplus
      66                 : /*
      67                 :  * C++ version is taken from chrome's basictypes.h, and renamed to
      68                 :  * avoid collision in case of multiple includes.  NACL_ARRAY_SIZE
      69                 :  * relies on template matching failure if the argument is not an
      70                 :  * array.
      71                 :  */
      72                 : template <typename T, size_t N>
      73                 : char (&NaClArraySizeHelper(T (&array)[N]))[N];
      74                 : 
      75                 : #ifndef _MSC_VER
      76                 : template <typename T, size_t N>
      77                 : char (&NaClArraySizeHelper(const T (&array)[N]))[N];
      78                 : #endif  /* _MSC_VER */
      79                 : 
      80                 : #define NACL_ARRAY_SIZE(array) (sizeof(NaClArraySizeHelper(array)))
      81                 : 
      82                 : /*
      83                 :  * Dead code elimination will get rid of this if there are no
      84                 :  * compile-time errors generated by ARRAY_SIZE.
      85                 :  */
      86                 : #define NACL_ASSERT_IS_ARRAY(array)                     \
      87                 :   do {                                                  \
      88                 :     char __array__[NACL_ARRAY_SIZE(array)];             \
      89                 :     if (0 == sizeof __array__) {                        \
      90                 :       abort();                                          \
      91                 :     }                                                   \
      92                 :   } while (0)
      93                 : 
      94                 : #else  /* __cplusplus */
      95                 : 
      96                 : /*
      97                 :  * The C version uses the fact that __builtin_types_compatible_p can
      98                 :  * be used to discriminate between T * and T *const.  (Note that this
      99                 :  * difference is not a top-level qualifier difference as mentioned in
     100                 :  * the gcc info node; that would apply to T * versus T const *.)  In
     101                 :  * the assertion statement version (NACL_ASSERT_IS_ARRAY), we use this
     102                 :  * to allocate an array, and ISO C forbids a zero-sized (or
     103                 :  * negative-sized) array.  In the expression version (ARRAY_SIZE), we
     104                 :  * assign to a global void * -- assigning a zero is fine, but
     105                 :  * assigning a 1 results in a warning that making a pointer from an
     106                 :  * integer is verboten.  When ARRAY_SIZE is used in a loop control
     107                 :  * context, e.g.,
     108                 :  *
     109                 :  * for (ix = 0; ix < ARRAY_SIZE(arr); ++ix) { ... }
     110                 :  *
     111                 :  * with -O the optimizer recognizes that the store can be moved out of
     112                 :  * the loop, so the performance impact should be minimal.
     113                 :  */
     114                 : # if __GNUC__
     115                 : #  define NACL_ASSERT_IS_ARRAY(arr)                           \
     116                 :   do {                                                        \
     117                 :     char __is_array__[1-2*__builtin_types_compatible_p(       \
     118                 :         __typeof__(&arr[0]),                                  \
     119                 :         __typeof__(arr))];                                    \
     120                 :     /* dead code, but gets rid of unused-variable warnings */ \
     121                 :     if (0 == sizeof __is_array__) {                           \
     122                 :       abort();                                                \
     123                 :     }                                                         \
     124                 :   } while (0)
     125                 : 
     126          651209 : static inline void *NaClArrayCheckHelper(void *arg) {
     127                 :   /*
     128                 :    * Doing runtime checks is not really necessary -- this code is in
     129                 :    * fact unreachable code that gets optimized out when used with the
     130                 :    * NACL_ARRAY_SIZE definition below.
     131                 :    *
     132                 :    * The runtime check is only useful when the build system is using
     133                 :    * the inappropriate flags (e.g., missing -pedantic -Werror or
     134                 :    * -pedantic-error), in which case instead of a compile-time error,
     135                 :    * we'd get a runtime error.
     136                 :    */
     137          651209 :   if (NULL != arg) {
     138               0 :     abort();
     139                 :   }
     140          651209 :   return arg;
     141                 : }
     142                 : 
     143                 : #  define NACL_ARRAY_SIZE(arr)                                         \
     144                 :   (NaClArrayCheckHelper(                                               \
     145                 :       __builtin_types_compatible_p(__typeof__(&arr[0]),                \
     146                 :                                    __typeof__(arr))),                  \
     147                 :   NACL_ARRAY_SIZE_UNSAFE(arr))
     148                 : # else  /* __GNUC__ */
     149                 : 
     150                 : /*
     151                 :  * Not gcc.  So far, we only compile NaCl under gcc and visual studio,
     152                 :  * but if/when a new compiler is introduced that's capable of doing
     153                 :  * compile-time checking (or we figure out how to do it w/ visual
     154                 :  * studio), check for those compilers here, and enable the
     155                 :  * corresponding compile-failure tests in
     156                 :  * src/trusted/service_runtime/build.scons.
     157                 :  */
     158                 : 
     159                 : #  define NACL_ASSERT_IS_ARRAY(arr)
     160                 : #  define NACL_ARRAY_SIZE(arr) NACL_ARRAY_SIZE_UNSAFE(arr)
     161                 : # endif  /* __GNUC__ */
     162                 : #endif  /* __cplusplus */
     163                 : 
     164                 : /*
     165                 :  * NACL_ASSERT_IS_POINTER(arr) generates a somewhat opaque compile-time
     166                 :  * error if lvalue is not a pointer lvalue but is instead an actual
     167                 :  * array (which is a T * const object).  This is complementary to
     168                 :  * NACL_ASSERT_IS_ARRAY.
     169                 :  */
     170                 : #define NACL_ASSERT_IS_POINTER(ptr) do { if (0) { ++ptr; } } while (0)
     171                 : 
     172                 : /*
     173                 :  * NACL_ASSERT_SAME_SIZE(t1, t2) verifies that the two types have the same size
     174                 :  * (as reported by sizeof).  When the check fails it generates a somewhat
     175                 :  * opaque warning, mitigated by the variable's name.
     176                 :  *
     177                 :  * Examples:
     178                 :  *   NACL_ASSERT_SAME_SIZE(void *, char *);  // Likely to succeed!
     179                 :  *   NACL_ASSERT_SAME_SIZE(char, long);  // Unlikely to succeed
     180                 :  */
     181                 : #define NACL_ASSERT_SAME_SIZE(t1, t2) \
     182                 :   do { char tested_types_are_not_the_same_size[sizeof(t1) == sizeof(t2)]; \
     183                 :        (void) tested_types_are_not_the_same_size; } while (0)
     184                 : 
     185                 : 
     186                 : /*
     187                 :  * NACL_COMPILE_TIME_ASSERT(boolexp) verifies that the argument
     188                 :  * boolexp is true.  The check occurs at compile time, assuming
     189                 :  * -pedantic flag or similar is used so that the ISO C forbidden
     190                 :  * zero-sized array generates an error.  This is standard with NaCl
     191                 :  * code.  If the wrong compilation flags are used, then we would get a
     192                 :  * run-time abort.
     193                 :  *
     194                 :  * Example:
     195                 :  *
     196                 :  * NACL_COMPILE_TIME_ASSERT(NACL_MAX_VAL(int32_t) <= SIZE_T_MAX)
     197                 :  *
     198                 :  * to explicitly state the assumption that an int32_t expression -- if
     199                 :  * containing a non-negative number -- will fit in a size_t variable.
     200                 :  */
     201                 : #define NACL_COMPILE_TIME_ASSERT(boolexp)                          \
     202                 :   do {                                                             \
     203                 :     char compile_time_boolean_expression_is_false[0 != (boolexp)]; \
     204                 :     if (0 == sizeof compile_time_boolean_expression_is_false) {    \
     205                 :       abort();                                                     \
     206                 :     }                                                              \
     207                 :   } while (0)
     208                 : 
     209                 : /*****************************************************************************
     210                 :  * MAX/MIN macros for integral types                                         *
     211                 :  ****************************************************************************/
     212                 : 
     213                 : /*
     214                 :  * For NACL_MAX_VAL, T must be a type where u ## T is the unsigned
     215                 :  * version of the type.
     216                 :  *
     217                 :  * These macros rely on -1 being signed extended to the width of T (or
     218                 :  * u ## T), and on two's complement representation of integers.
     219                 :  *
     220                 :  * Generally, stdint.h's INT16_MAX etc can be used, but these are
     221                 :  * useful for macros that take a type parameter and need the max or
     222                 :  * min value for the type, since then the macro would not have to also take
     223                 :  * the max or min value as additional parameter(s).
     224                 :  */
     225                 : #define NACL_UMAX_VAL(T)  ((T) -1)
     226                 : #define NACL_MAX_VAL(T)   ((T) (((u ## T) -1) >> 1))
     227                 : #define NACL_UMIN_VAL(T)  ((T) 0)
     228                 : #define NACL_MIN_VAL(T)   ((T) ~NACL_MAX_VAL(T))
     229                 : 
     230                 : 
     231                 : /*****************************************************************************
     232                 :  * Readability macros                                                        *
     233                 :  ****************************************************************************/
     234                 : 
     235                 : #define NACL_NANOS_PER_MICRO          (1000)
     236                 : #define NACL_100_NANOS_PER_MILLI      (10 * 1000)
     237                 : #define NACL_NANOS_PER_MILLI          (1000 * 1000)
     238                 : #define NACL_MICROS_PER_MILLI         (1000)
     239                 : #define NACL_NANOS_PER_UNIT           (1000 * 1000 * 1000)
     240                 : #define NACL_MICROS_PER_UNIT          (1000 * 1000)
     241                 : #define NACL_MILLIS_PER_UNIT          (1000)
     242                 : #define NACL_UNIT_CONVERT_ROUND(v, m) (((v) + (m) - 1)/(m))
     243                 : 
     244                 : #define NACL_NO_FILE_DESC             (-1)
     245                 : #define NACL_NO_URL                   ""
     246                 : #define NACL_NO_FILE_PATH             ""
     247                 : 
     248                 : #define NACL_HTTP_STATUS_OK           200
     249                 : 
     250                 : /*****************************************************************************
     251                 :  * C++ coding convention macros                                              *
     252                 :  ****************************************************************************/
     253                 : 
     254                 : #ifdef __cplusplus
     255                 : /*
     256                 :  * A macro to disallow the copy constructor and operator= functions
     257                 :  * This should be used in the private: declarations for a class
     258                 :  */
     259                 : #define NACL_DISALLOW_COPY_AND_ASSIGN(TypeName) \
     260                 :     TypeName(const TypeName&);                  \
     261                 :     void operator=(const TypeName&)
     262                 : 
     263                 : /* A macro to use in place of unimplemented sections of code. */
     264                 : #define NACL_UNIMPLEMENTED()                                       \
     265                 :     fprintf(stderr, "%s:%d: unimplemented\n", __FILE__, __LINE__); \
     266                 :     exit(1);
     267                 : 
     268                 : /* A macro to use to detect when control reaches a statement it should not. */
     269                 : #define NACL_NOTREACHED()                                                  \
     270                 :     fprintf(stderr, "%s:%d: should not reach here\n", __FILE__, __LINE__); \
     271                 :     exit(1);
     272                 : 
     273                 : /* A macro to mark code that has not been tested manually or automatically. */
     274                 : #define NACL_UNTESTED()                                                    \
     275                 :     fprintf(stderr, "%s:%d: reached untested code\n", __FILE__, __LINE__); \
     276                 :     exit(1);
     277                 : 
     278                 : // nacl_bit_cast<Dest,Source> is a template function that implements the
     279                 : // equivalent of "*reinterpret_cast<Dest*>(&source)".  We need this in
     280                 : // very low-level functions like the protobuf library and fast math
     281                 : // support.
     282                 : //
     283                 : //   float f = 3.14159265358979;
     284                 : //   int i = nacl_bit_cast<int32>(f);
     285                 : //   // i = 0x40490fdb
     286                 : //
     287                 : // The classical address-casting method is:
     288                 : //
     289                 : //   // WRONG
     290                 : //   float f = 3.14159265358979;            // WRONG
     291                 : //   int i = * reinterpret_cast<int*>(&f);  // WRONG
     292                 : //
     293                 : // The address-casting method actually produces undefined behavior
     294                 : // according to ISO C++ specification section 3.10 -15 -.  Roughly, this
     295                 : // section says: if an object in memory has one type, and a program
     296                 : // accesses it with a different type, then the result is undefined
     297                 : // behavior for most values of "different type".
     298                 : //
     299                 : // This is true for any cast syntax, either *(int*)&f or
     300                 : // *reinterpret_cast<int*>(&f).  And it is particularly true for
     301                 : // conversions betweeen integral lvalues and floating-point lvalues.
     302                 : //
     303                 : // The purpose of 3.10 -15- is to allow optimizing compilers to assume
     304                 : // that expressions with different types refer to different memory.  gcc
     305                 : // 4.0.1 has an optimizer that takes advantage of this.  So a
     306                 : // non-conforming program quietly produces wildly incorrect output.
     307                 : //
     308                 : // The problem is not the use of reinterpret_cast.  The problem is type
     309                 : // punning: holding an object in memory of one type and reading its bits
     310                 : // back using a different type.
     311                 : //
     312                 : // The C++ standard is more subtle and complex than this, but that
     313                 : // is the basic idea.
     314                 : //
     315                 : // Anyways ...
     316                 : //
     317                 : // nacl_bit_cast<> calls memcpy() which is blessed by the standard,
     318                 : // especially by the example in section 3.9 .  Also, of course,
     319                 : // nacl_bit_cast<> wraps up the nasty logic in one place.
     320                 : //
     321                 : // Fortunately memcpy() is very fast.  In optimized mode, with a
     322                 : // constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
     323                 : // code with the minimal amount of data movement.  On a 32-bit system,
     324                 : // memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
     325                 : // compiles to two loads and two stores.
     326                 : //
     327                 : // I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
     328                 : //
     329                 : // WARNING: if Dest or Source is a non-POD type, the result of the memcpy
     330                 : // is likely to surprise you.
     331                 : 
     332                 : template <class Dest, class Source>
     333                 : inline Dest nacl_bit_cast(const Source& source) {
     334                 :   // Compile time assertion: sizeof(Dest) == sizeof(Source)
     335                 :   // A compile error here means your Dest and Source have different sizes.
     336                 :   typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
     337                 : 
     338                 :   Dest dest;
     339                 :   memcpy(&dest, &source, sizeof(dest));
     340                 :   return dest;
     341                 : }
     342                 : 
     343                 : #endif  /* __cplusplus */
     344                 : 
     345                 : #endif  /* NATIVE_CLIENT_SRC_INCLUDE_NACL_MACROS_H_ */

Generated by: LCOV version 1.7