diff --git a/scan/scan_8int.c b/scan/scan_8int.c index dba3be4..868faa0 100644 --- a/scan/scan_8int.c +++ b/scan/scan_8int.c @@ -1,8 +1,14 @@ #include "scan.h" size_t scan_8int(const char* src,unsigned int* dest) { - unsigned long l; - size_t len=scan_8long(src,&l); + register const char *tmp=src; + register unsigned int l=0; + register unsigned char c; + while ((c=*tmp-'0')<8) { + if (l>>(sizeof(l)*8-3)) break; + l=l*8+c; + ++tmp; + } *dest=l; - return len; + return tmp-src; } diff --git a/scan/scan_8longn.c b/scan/scan_8longn.c index 61885d6..7d500d4 100644 --- a/scan/scan_8longn.c +++ b/scan/scan_8longn.c @@ -5,6 +5,7 @@ size_t scan_8longn(const char *src,size_t n,unsigned long *dest) { register unsigned long l=0; register unsigned char c; while (n-->0 && (c=*tmp-'0')<8) { + if (l>>(sizeof(l)*8-3)) break; l=l*8+c; ++tmp; } diff --git a/scan/scan_8short.c b/scan/scan_8short.c index b3cf0f3..b83837d 100644 --- a/scan/scan_8short.c +++ b/scan/scan_8short.c @@ -1,8 +1,14 @@ #include "scan.h" size_t scan_8short(const char* src,unsigned short* dest) { - unsigned long l; - size_t len=scan_8long(src,&l); + register const char *tmp=src; + register unsigned short l=0; + register unsigned char c; + while ((c=*tmp-'0')<8) { + if (l>>(sizeof(l)*8-3)) break; + l=l*8+c; + ++tmp; + } *dest=l; - return len; + return tmp-src; } diff --git a/scan/scan_int.c b/scan/scan_int.c index 137cf55..4f82f0b 100644 --- a/scan/scan_int.c +++ b/scan/scan_int.c @@ -1,8 +1,38 @@ #include "scan.h" +static const unsigned int maxint = ((unsigned int)-1)>>1; + size_t scan_int(const char* src,int* dest) { - long l; - size_t len=scan_long(src,&l); - if (len) *dest=l; - return len; + register const char *tmp; + register int l; + register unsigned char c; + int neg; + int ok; + tmp=src; l=0; ok=neg=0; + switch (*tmp) { + case '-': neg=1; + case '+': ++tmp; + } + while ((c=(unsigned char)(*tmp-'0'))<10) { + unsigned long int n; + /* we want to do: l=l*10+c + * but we need to check for integer overflow. + * to check whether l*10 overflows, we could do + * if ((l*10)/10 != l) + * however, multiplication and division are expensive. + * so instead of *10 we do (l<<3) (i.e. *8) + (l<<1) (i.e. *2) + * and check for overflow on all the intermediate steps */ + n=(unsigned int)l<<3; if ((n>>3)!=(unsigned int)l) break; + if (n+(l<<1) < n) break; + n+=l<<1; + if (n+c < n) break; + n+=c; + if (n > maxint+neg) break; + l=n; + ++tmp; + ok=1; + } + if (!ok) return 0; + *dest=(neg?-l:l); + return (size_t)(tmp-src); } diff --git a/scan/scan_longn.c b/scan/scan_longn.c index c6e913e..f1c0a92 100644 --- a/scan/scan_longn.c +++ b/scan/scan_longn.c @@ -1,5 +1,7 @@ #include "scan.h" +static const unsigned long maxlong = ((unsigned long)-1)>>1; + size_t scan_longn(const char *src,size_t n,long *dest) { register const char *tmp; register long int l; @@ -12,12 +14,26 @@ size_t scan_longn(const char *src,size_t n,long *dest) { case '-': neg=1; case '+': ++tmp; } - while (n-->0 && (c=*tmp-'0')<10) { - l=l*10+c; + while (n-->0 && (c=(unsigned char)(*tmp-'0'))<10) { + unsigned long int n; + /* we want to do: l=l*10+c + * but we need to check for integer overflow. + * to check whether l*10 overflows, we could do + * if ((l*10)/10 != l) + * however, multiplication and division are expensive. + * so instead of *10 we do (l<<3) (i.e. *8) + (l<<1) (i.e. *2) + * and check for overflow on all the intermediate steps */ + n=(unsigned long)l<<3; if ((n>>3)!=(unsigned long)l) break; + if (n+(l<<1) < n) break; + n+=l<<1; + if (n+c < n) break; + n+=c; + if (n > maxlong+neg) break; + l=n; ++tmp; ok=1; } if (!ok) return 0; *dest=(neg?-l:l); - return tmp-src; + return (size_t)(tmp-src); } diff --git a/scan/scan_short.c b/scan/scan_short.c index a029ccf..14051bd 100644 --- a/scan/scan_short.c +++ b/scan/scan_short.c @@ -1,8 +1,38 @@ #include "scan.h" +static const unsigned int maxshort = ((unsigned short)-1)>>1; + size_t scan_short(const char* src,short* dest) { - long l; - size_t len=scan_long(src,&l); - *dest=l; - return len; + register const char *tmp; + register short l; + register unsigned char c; + int neg; + int ok; + tmp=src; l=0; ok=neg=0; + switch (*tmp) { + case '-': neg=1; + case '+': ++tmp; + } + while ((c=(unsigned char)(*tmp-'0'))<10) { + unsigned long int n; + /* we want to do: l=l*10+c + * but we need to check for integer overflow. + * to check whether l*10 overflows, we could do + * if ((l*10)/10 != l) + * however, multiplication and division are expensive. + * so instead of *10 we do (l<<3) (i.e. *8) + (l<<1) (i.e. *2) + * and check for overflow on all the intermediate steps */ + n=(unsigned int)l<<3; if ((n>>3)!=(unsigned int)l) break; + if (n+(l<<1) < n) break; + n+=l<<1; + if (n+c < n) break; + n+=c; + if (n > maxshort+neg) break; + l=n; + ++tmp; + ok=1; + } + if (!ok) return 0; + *dest=(neg?-l:l); + return (size_t)(tmp-src); } diff --git a/scan/scan_ushort.c b/scan/scan_ushort.c index 8b969a9..bdfd4fa 100644 --- a/scan/scan_ushort.c +++ b/scan/scan_ushort.c @@ -20,7 +20,7 @@ size_t scan_ushort(const char* src,unsigned short* dest) { n=l<<3; if ((n>>3)!=l) break; if (n+(l<<1) < n) break; n+=l<<1; - if (n+c < n) break; + if ((unsigned short)(n+c) < n) break; l=n+c; ++tmp; } diff --git a/scan/scan_xint.c b/scan/scan_xint.c index f55f9fc..5564a23 100644 --- a/scan/scan_xint.c +++ b/scan/scan_xint.c @@ -1,8 +1,13 @@ #include "scan.h" size_t scan_xint(const char* src,unsigned int* dest) { - unsigned long l; - register int len=scan_xlong(src,&l); + register const char *tmp=src; + register unsigned int l=0; + register unsigned char c; + while ((l>>(sizeof(l)*8-4))==0 && (c=scan_fromhex(*tmp))<16) { + l=(l<<4)+c; + ++tmp; + } *dest=l; - return len; + return tmp-src; } diff --git a/scan/scan_xlongn.c b/scan/scan_xlongn.c index a24cf67..7618ac5 100644 --- a/scan/scan_xlongn.c +++ b/scan/scan_xlongn.c @@ -4,7 +4,7 @@ size_t scan_xlongn(const char *src,size_t n,unsigned long *dest) { register const char *tmp=src; register unsigned long l=0; register unsigned char c; - while (n-->0 && (c=scan_fromhex(*tmp))<16) { + while (n-->0 && (l>>(sizeof(l)*8-4))==0 && (c=scan_fromhex(*tmp))<16) { l=(l<<4)+c; ++tmp; } diff --git a/scan/scan_xshort.c b/scan/scan_xshort.c index a66ef5a..82c3cc6 100644 --- a/scan/scan_xshort.c +++ b/scan/scan_xshort.c @@ -1,8 +1,13 @@ #include "scan.h" size_t scan_xshort(const char* src,unsigned short* dest) { - unsigned long l; - size_t len=scan_xlong(src,&l); + register const char *tmp=src; + register unsigned short l=0; + register unsigned char c; + while ((l>>(sizeof(l)*8-4))==0 && (c=scan_fromhex(*tmp))<16) { + l=(l<<4)+c; + ++tmp; + } *dest=l; - return len; + return tmp-src; } diff --git a/test/marshal.c b/test/marshal.c index 8a0f322..9b060c1 100644 --- a/test/marshal.c +++ b/test/marshal.c @@ -11,6 +11,17 @@ void zap() { size_t i; for (i=0; i