Mirror of :pserver:cvs@cvs.fefe.de:/cvs libowfat https://www.fefe.de/libowfat/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

178 lines
6.7 KiB

  1. /* this header file comes from libowfat, http://www.fefe.de/libowfat/ */
  2. #ifndef RANGECHECK_H
  3. #define RANGECHECK_H
  4. #include <inttypes.h>
  5. #include <stddef.h>
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /* We are trying to achieve that gcc has to inline the function and we
  10. * don't want it to emit a copy of the function. This can be done with
  11. * static inline or with extern inline. static inline tells gcc to not
  12. * emit a copy unless someone is using & to take a pointer, which nobody
  13. * is ever supposed to do. extern inline tells gcc to not ever emit a
  14. * copy.
  15. *
  16. * Unfortunately, the C99 standard defines extern inline to mean "always
  17. * emit a copy for external reference", so this causes duplicate symbol
  18. * linking errors. gcc signals C99 inline expansion mode by defining
  19. * __GNUC_STDC_INLINE__ and it then has an attribute gnu_inline to
  20. * switch back to GNU behavior. So that's what we are doing. Taking
  21. * the address of one of these functions is considered a user error.
  22. *
  23. * We are so anal about inlining here because these checks can in most
  24. * cases be optimized away. In particular, if you call this function
  25. * often, gcc can see that some of the basic checks are done repeatedly
  26. * and not do them again. But this only works if the function is
  27. * inlined. */
  28. #if defined(__GNUC_STDC_INLINE__)
  29. #define __gnuinline __attribute__((gnu_inline))
  30. #else
  31. #define __gnuinline
  32. #endif
  33. #if defined(__GNUC__) && !defined(__NO_INLINE__) && !defined(__clang__)
  34. #define __static extern
  35. #else
  36. #define __static static
  37. #endif
  38. #if !defined(__GNUC__) || (__GNUC__ < 3)
  39. #define __builtin_expect(foo,bar) (foo)
  40. #define __expect(foo,bar) (foo)
  41. #else
  42. #define __expect(foo,bar) __builtin_expect((long)(foo),bar)
  43. #endif
  44. #if defined(__GNUC__) && !defined(__likely)
  45. #define __likely(foo) __expect((foo),1)
  46. #define __unlikely(foo) __expect((foo),0)
  47. #endif
  48. #if !defined(__likely)
  49. #define __likely(foo) (foo)
  50. #define __unlikely(foo) (foo)
  51. #endif
  52. /* return 0 for range error / overflow, 1 for ok */
  53. /* we assume the normal case is that the checked value is in range */
  54. /* does ptr point to one of buf[0], buf[1], ... buf[len-1]? */
  55. __static inline __gnuinline int range_ptrinbuf(const void* buf,size_t len,const void* ptr) {
  56. register const char* c=(const char*)buf; /* no pointer arithmetic on void* */
  57. return __likely(c && /* is buf non-NULL? */
  58. ((uintptr_t)c)+len>(uintptr_t)c && /* gcc 4.1 miscompiles without (uintptr_t) */
  59. /* catch integer overflows and fail if buffer is 0 bytes long */
  60. /* because then ptr can't point _in_ the buffer */
  61. (uintptr_t)((const char*)ptr-c)<len); /* this one is a little tricky.
  62. "ptr-c" checks the offset of ptr in the buffer is inside the buffer size.
  63. Now, ptr-c can underflow; say it is -1. When we cast it to uintptr_t, it becomes
  64. a very large number. */
  65. }
  66. /* same thing, but the buffer is specified by a pointer to the first
  67. * byte (Min) and a pointer after the last byte (Max). */
  68. __static inline __gnuinline int range_ptrinbuf2(const void* Min,const void* Max,const void* ptr) {
  69. return __likely(Min && ptr>=Min && ptr<Max);
  70. /* Min <= Max is implicitly checked here */
  71. }
  72. /* Is this a plausible buffer?
  73. * Check whether buf is NULL, and whether buf+len overflows.
  74. * Does NOT check whether buf has a non-zero length! */
  75. __static inline __gnuinline int range_validbuf(const void* buf,size_t len) {
  76. return __likely(buf && (uintptr_t)buf+len>=(uintptr_t)buf);
  77. }
  78. /* same thing but buffer is given as pointer to first byte (Min) and
  79. * pointer beyond last byte (Max). Again, an 0-size buffer is valid. */
  80. __static inline __gnuinline int range_validbuf2(const void* Min,const void* Max) {
  81. return __likely(Min && Max>=Min);
  82. }
  83. /* is buf2[0..len2-1] inside buf1[0..len-1]? */
  84. __static inline __gnuinline int range_bufinbuf(const void* buf1,size_t len1,const void* buf2,size_t len2) {
  85. return range_validbuf(buf1,len1) &&
  86. range_validbuf(buf2,len2) &&
  87. __likely(buf1<=buf2 &&
  88. (ptrdiff_t)buf1+len1>=(ptrdiff_t)buf2+len2);
  89. }
  90. /* does an array of "elements" members of size "membersize" starting at
  91. * "arraystart" lie inside buf1[0..len-1]? */
  92. int range_arrayinbuf(const void* buf,size_t len,
  93. const void* arraystart,size_t elements,size_t membersize);
  94. /* does an ASCIIZ string starting at "ptr" lie in buf[0..len-1]? */
  95. int range_strinbuf(const void* buf,size_t len,const void* stringstart);
  96. /* does an UTF-16 string starting at "ptr" lie in buf[0..len-1]? */
  97. int range_str2inbuf(const void* buf,size_t len,const void* stringstart);
  98. /* does an UTF-32 string starting at "ptr" lie in buf[0..len-1]? */
  99. int range_str4inbuf(const void* buf,size_t len,const void* stringstart);
  100. /* I originally omitted addition and substraction because it appeared
  101. * trivial. You could just add the two numbers and see if it was
  102. * smaller than either of them. This always worked for me because I
  103. * only cared about unsigned arithmetic, but for signed arithmetic,
  104. * adding two numbers is undefined if the result does not fit in the
  105. * int. gcc has started to actually use this undefinedness to screw
  106. * you. The following code illustrates this:
  107. * int a=INT_MAX,b=a+5;
  108. * if (b<a) abort(); // whole statement optimized away by gcc 4.1
  109. * // at this point, b<a
  110. * So I decided to add some integer overflow protection functionality
  111. * here for addition and subtraction, too. */
  112. /* usage:
  113. * if (add_of(dest,a,b)) return EINVAL; // dest=a+b;
  114. * if (sub_of(dest,a,b)) return EINVAL; // dest=a-b;
  115. * if (assign(dest,some_int)) return EINVAL; // dest=some_int;
  116. */
  117. /* two important assumptions:
  118. * 1. the platform is using two's complement
  119. * 2. there are 8 bits in a byte
  120. */
  121. #define __HALF_MAX_SIGNED(type) ((type)1 << (sizeof(type)*8-2))
  122. #define __MAX_SIGNED(type) (__HALF_MAX_SIGNED(type) - 1 + __HALF_MAX_SIGNED(type))
  123. #define __MIN_SIGNED(type) (-1 - __MAX_SIGNED(type))
  124. /* we use <1 and not <0 to avoid a gcc warning */
  125. #define __MIN(type) ((type)-1 < 1?__MIN_SIGNED(type):(type)0)
  126. #define __MAX(type) ((type)~__MIN(type))
  127. #define assign(dest,src) ({ typeof(src) __x=(src); typeof(dest) __y=__x; (__x==__y && ((__x<1) == (__y<1))?(void)((dest)=__y),0:1); })
  128. /* gcc 5 now has nice builtins we can use instead */
  129. #if defined(__GNUC__) && (__GNUC__ >= 5)
  130. #define add_of(c,a,b) __builtin_add_overflow(a,b,&c)
  131. #define sub_of(c,a,b) __builtin_sub_overflow(a,b,&c)
  132. #else
  133. /* if a+b is defined and does not have an integer overflow, do c=a+b and
  134. * return 0. Otherwise, return 1. */
  135. #define add_of(c,a,b) ({ typeof(a) __a=a; typeof(b) __b=b; (__b)<1?((__MIN(typeof(a+b))-(__b)<=(__a))?assign(c,__a+__b):1) : ((__MAX(typeof(c))-(__b)>=(__a))?assign(c,__a+__b):1); })
  136. #define sub_of(c,a,b) ({ typeof(a) __a=a; typeof(b) __b=b; (__b)<1?((__MAX(typeof(a+b))+__b>=__a)?assign(c,__a-__b):1) : ((__MIN(typeof(c))+__b<=__a)?assign(c,__a-__b):1); })
  137. #endif
  138. #undef __static
  139. #ifdef __cplusplus
  140. }
  141. #endif
  142. #endif