Browse Source

do proper early abort in the other scan_* routines if the numeric value

is too large
master
Felix von Leitner 8 years ago
parent
commit
826abd7560
  1. 12
      scan/scan_8int.c
  2. 1
      scan/scan_8longn.c
  3. 12
      scan/scan_8short.c
  4. 38
      scan/scan_int.c
  5. 22
      scan/scan_longn.c
  6. 38
      scan/scan_short.c
  7. 2
      scan/scan_ushort.c
  8. 11
      scan/scan_xint.c
  9. 2
      scan/scan_xlongn.c
  10. 11
      scan/scan_xshort.c
  11. 78
      test/marshal.c

12
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;
}

1
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;
}

12
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;
}

38
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);
}

22
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);
}

38
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);
}

2
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;
}

11
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;
}

2
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;
}

11
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;
}

78
test/marshal.c

@ -11,6 +11,17 @@ void zap() { size_t i; for (i=0; i<sizeof(buf); ++i) buf[i]='_'; }
int main() {
uint32_t x;
unsigned long long ull;
unsigned long ul;
unsigned int ui;
unsigned short us;
unsigned char uc;
signed long long ll;
signed long l;
signed int i;
signed short s;
signed char c;
// check utf8 encoding
zap(); assert(fmt_utf8(NULL,12345) == 3);
zap(); assert(fmt_utf8(buf,12345) == 3 && byte_equal(buf,4,"\xe3\x80\xb9_"));
@ -128,4 +139,71 @@ int main() {
assert(fmt_escapecharquotedprintableutf8(NULL,0xf6)==6); // =c3=b6
zap(); assert(fmt_escapecharquotedprintableutf8(buf,0xf6)==6 && byte_equal(buf,7,"=c3=b6_"));
assert(scan_ulong("23",&ul)==2 && ul==23);
assert(scan_ulong("46halbe",&ul)==2 && ul==46);
if (sizeof(ul)==4) {
assert(scan_ulong("4294967295",&ul)==10 && ul==0xffffffff);
assert(scan_ulong("4294967296",&ul)==9 && ul==429496729);
assert(scan_xlong("ffffffff",&ul)==8 && ul==0xffffffff);
assert(scan_xlong("ffffffff0",&ul)==8 && ul==0xffffffff);
assert(scan_8long("37777777777",&ul)==11 && ul==0xffffffff);
assert(scan_8long("377777777771",&ul)==11 && ul==0xffffffff);
assert(scan_long("2147483647",&l)==10 && l==0x7fffffff);
assert(scan_long("02147483647",&l)==11 && l==0x7fffffff);
assert(scan_long("021474836470",&l)==11 && l==0x7fffffff);
assert(scan_long("+2147483647",&l)==11 && l==0x7fffffff);
assert(scan_long("+2147483648",&l)==10 && l==214748364);
assert(scan_long("-2147483647",&l)==11 && l==-2147483647);
assert(scan_long("-2147483648",&l)==11 && l==-2147483648);
assert(scan_long("-2147483649",&l)==10 && l==-214748364);
} else {
assert(scan_ulong("18446744073709551615",&ul)==20 && ul==0xffffffffffffffffull);
assert(scan_ulong("18446744073709551616",&ul)==19 && ul==1844674407370955161ull);
assert(scan_xlong("ffffffffffffffff",&ul)==16 && ul==0xffffffffffffffffull);
assert(scan_xlong("ffffffffffffffff0",&ul)==16 && ul==0xffffffffffffffffull);
assert(scan_8long("1777777777777777777777",&ul)==22 && ul==0xffffffffffffffffull);
assert(scan_8long("17777777777777777777770",&ul)==22 && ul==0xffffffffffffffffull);
assert(scan_long("9223372036854775807",&l)==19 && l==0x7fffffffffffffffll);
assert(scan_long("09223372036854775807",&l)==20 && l==0x7fffffffffffffffll);
assert(scan_long("092233720368547758070",&l)==20 && l==0x7fffffffffffffffll);
assert(scan_long("+9223372036854775807",&l)==20 && l==0x7fffffffffffffffll);
assert(scan_long("+9223372036854775808",&l)==19 && l==922337203685477580ll);
assert(scan_long("-9223372036854775807",&l)==20 && l==-9223372036854775807ll);
x=scan_long("-9223372036854775808",&l);
assert(scan_long("-9223372036854775808",&l)==20 && l==0x8000000000000000);
assert(scan_long("-9223372036854775809",&l)==19 && l==-922337203685477580ll);
}
assert(scan_uint("4294967295",&ui)==10 && ui==0xffffffff);
assert(scan_uint("4294967296",&ui)==9 && ui==429496729);
assert(scan_ushort("65535",&us)==5 && us==0xffff);
assert(scan_ushort("65536",&us)==4 && us==6553);
assert(scan_xint("0ffffffff",&ui)==9 && ui==0xffffffff);
assert(scan_xint("ffffffff0",&ui)==8 && ui==0xffffffff);
assert(scan_xshort("0ffff",&us)==5 && us==0xffff);
assert(scan_xshort("ffff1",&us)==4 && us==0xffff);
assert(scan_8int("037777777777",&ui)==12 && ui==0xffffffff);
assert(scan_8int("377777777771",&ui)==11 && ui==0xffffffff);
assert(scan_8short("00177777",&us)==8 && us==0xffff);
assert(scan_8short("1777771",&us)==6 && us==0xffff);
assert(scan_int("2147483647",&i)==10 && i==0x7fffffff);
assert(scan_int("02147483647",&i)==11 && i==0x7fffffff);
assert(scan_int("021474836470",&i)==11 && i==0x7fffffff);
assert(scan_int("+2147483647",&i)==11 && i==0x7fffffff);
assert(scan_int("+2147483648",&i)==10 && i==214748364);
assert(scan_int("-2147483647",&i)==11 && i==-2147483647);
assert(scan_int("-2147483648",&i)==11 && i==-2147483648);
assert(scan_int("-2147483649",&i)==10 && i==-214748364);
assert(scan_short("32767",&s)==5 && s==32767);
assert(scan_short("32768",&s)==4 && s==3276);
assert(scan_short("+032767",&s)==7 && s==32767);
assert(scan_short("-32768",&s)==6 && s==-32768);
assert(scan_short("-032769",&s)==6 && s==-3276);
}

Loading…
Cancel
Save