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.

183 lines
6.8 KiB

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