diff --git a/CHANGES b/CHANGES index 84b9ef2..515e47b 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ start over from the beginning because always new accept()ed connections came in and got newer, higher descriptors since the last io_timeouted loop. (Dirk Engling) + add some int overflow check macros to rangecheck.h 0.25: array_allocate no longer truncates the array diff --git a/rangecheck.h b/rangecheck.h index 137be58..55a0684 100644 --- a/rangecheck.h +++ b/rangecheck.h @@ -54,6 +54,43 @@ int range_str2inbuf(const void* buf,size_t len,const void* stringstart); /* does an UTF-32 string starting at "ptr" lie in buf[0..len-1]? */ int range_str4inbuf(const void* buf,size_t len,const void* stringstart); + +/* I originally omitted addition and substraction because it appeared + * trivial. You could just add the two numbers and see if it was + * smaller than either of them. This always worked for me because I + * only cared about unsigned arithmetic, but for signed arithmetic, + * adding two numbers is undefined if the result does not fit in the + * int. gcc has started to actually use this undefinedness to screw + * you. The following code illustrates this: + * int a=INT_MAX,b=a+5; + * if (b=(__a))?assign(c,__a+__b):1); }) + +#define sub_of(c,a,b) ({ typeof(a) __a=a; typeof(b) __b=b; (__b)<1?((__MAX(typeof(c))-(__b)>=(__a))?assign(c,__a-__b):1) : ((__MIN(typeof(c))+(__b)<=(__a))?assign(c,__a-__b):1); }) + #undef __static #endif diff --git a/test/range.c b/test/range.c index 972d19b..ba4cca9 100644 --- a/test/range.c +++ b/test/range.c @@ -1,8 +1,54 @@ #include "rangecheck.h" #include #include +#include +#include -int main() { +void check_minmax() { + /* make sure the __MIN and __MAX macros work */ + assert(__MIN(signed char)==-128); + assert(__MAX(signed char)==127); + assert(__MIN(unsigned char)==0); + assert(__MAX(unsigned char)==255); + + assert(__MIN(short)==SHRT_MIN); + assert(__MAX(short)==SHRT_MAX); + assert(__MIN(unsigned short)==0); + assert(__MAX(unsigned short)==USHRT_MAX); + + assert(__MIN(int)==INT_MIN); + assert(__MAX(int)==INT_MAX); + assert(__MIN(unsigned int)==0); + assert(__MAX(unsigned int)==UINT_MAX); + + assert(__MIN(long)==LONG_MIN); + assert(__MAX(long)==LONG_MAX); + assert(__MIN(unsigned long)==0); + assert(__MAX(unsigned long)==ULONG_MAX); + +#ifdef LLONG_MIN + assert(__MIN(long long)==LLONG_MIN); + assert(__MAX(long long)==LLONG_MAX); + assert(__MIN(unsigned long long)==0); + assert(__MAX(unsigned long long)==ULLONG_MAX); +#endif + + assert(__MIN(int32_t)==(int32_t)0x80000000); + assert(__MAX(int32_t)==0x7fffffff); + assert(__MIN(uint32_t)==0); + assert(__MAX(uint32_t)==0xffffffff); +} + +void check_assign() { + int a; + assert(assign(a,5)==0 && a==5); + a=23; assert(assign(a,(unsigned int)-23)==1); +#ifdef LLONG_MIN + a=23; assert(assign(a,LLONG_MAX)==1); +#endif +} + +void check_rangeptrbuf() { char buf[1000]; /* does range_ptrinbuf check all the incoming pointer cases right? */ @@ -83,7 +129,75 @@ int main() { assert(range_str4inbuf(y,sizeof(y),y+5)==1); assert(range_str4inbuf(y,sizeof(y),y+6)==0); } +} + +void check_intof() { + /* since the macros are type independent, we only check one signed and + * one unsigned type */ + + /* some checks are redundant, but we want to cover off-by-one cases */ + { + int a; + a=0; assert(add_of(a,INT_MAX-3,1)==0 && a==INT_MAX-2); + a=0; assert(add_of(a,INT_MAX-3,5)==1); + a=0; assert(add_of(a,INT_MAX-3,3)==0 && a==INT_MAX); + a=0; assert(add_of(a,INT_MAX-3,4)==1); + a=0; assert(add_of(a,0,INT_MIN)==0 && a==INT_MIN); + a=0; assert(add_of(a,-1,INT_MIN)==1); + a=0; assert(add_of(a,1,INT_MAX)==1); + + /* now let's see what happens if the addition has a wider data + * type than the destionation */ + a=0; assert(add_of(a,0x100000000ll,-0x80000000ll)==1); + a=0; assert(add_of(a,0x100000000ll,-0x80000001ll)==0 && a==0x7fffffff); + a=0; assert(add_of(a,0x100000000ll,-10)==1); + a=0; assert(add_of(a,-0x90000000ll,0x10000000)==0 && a==0x80000000); + + /* what if we add two ints, the result does not overflow but is + * still negative, but we assign it to an unsigned int? */ + a=0; assert(add_of(a,0x7ffffff0,0x10)==1); + } + + { + unsigned int a; + a=0; assert(add_of(a,UINT_MAX-3,1)==0 && a==UINT_MAX-2); + a=0; assert(add_of(a,UINT_MAX-3,5)==1); + a=0; assert(add_of(a,UINT_MAX-3,4)==1); + a=0; assert(add_of(a,2,-3)==1); + a=23; assert(add_of(a,2,-2)==0 && a==0); + a=0; assert(add_of(a,(int)0x80000000,(int)-2147483648)==0 && a==0); + a=0; assert(add_of(a,(int)0x7fffffff,(int)-2147483648)==1); + a=0; assert(add_of(a,1,UINT_MAX)==1); + + /* now let's see what happens if the addition has a wider data + * type than the destionation */ + a=0; assert(add_of(a,0x100000000ll,-5)==0 && a==4294967291); + a=0; assert(add_of(a,-0x100000010ll,5)==1); + a=0; assert(add_of(a,0x100000010ll,-5)==1); + + /* what if we add two ints, the result does not overflow but is + * still negative, but we assign it to an unsigned int? */ + a=0; assert(add_of(a,-10,-5)==1); + } + + { + int a; + a=0; assert(sub_of(a,10,5)==0 && a==5); + a=0; assert(sub_of(a,5,10)==0 && a==-5); + a=0; assert(sub_of(a,INT_MIN,10)==1); + a=0; assert(sub_of(a,INT_MIN,-10)==0 && a==INT_MIN+10); + a=0; assert(sub_of(a,INT_MAX,-10)==1); + a=0; assert(sub_of(a,INT_MAX,10)==0 && a==INT_MAX-10); + } + +} + +int main() { + check_minmax(); + check_assign(); + check_intof(); + check_rangeptrbuf(); puts("all tests ok"); return 0;