diff options
author | Antony Dovgal <tony2001@php.net> | 2007-04-22 21:33:10 +0000 |
---|---|---|
committer | Antony Dovgal <tony2001@php.net> | 2007-04-22 21:33:10 +0000 |
commit | f6cef916bc36e60c3c92e09e9264a0a28d24a30d (patch) | |
tree | a0db47034fe37b3b652ba0171803c6f580822310 | |
parent | e910699347be2deeaa1fada69b183bdace1d962a (diff) | |
download | php-git-f6cef916bc36e60c3c92e09e9264a0a28d24a30d.tar.gz |
MFH: fix #41118 (PHP does not handle overflow of octal integers)
-rw-r--r-- | Zend/tests/hex_overflow_32bit.phpt | 27 | ||||
-rw-r--r-- | Zend/tests/oct_overflow_32bit.phpt | 29 | ||||
-rw-r--r-- | Zend/zend_language_scanner.l | 6 | ||||
-rw-r--r-- | Zend/zend_strtod.c | 28 | ||||
-rw-r--r-- | Zend/zend_strtod.h | 1 |
5 files changed, 90 insertions, 1 deletions
diff --git a/Zend/tests/hex_overflow_32bit.phpt b/Zend/tests/hex_overflow_32bit.phpt new file mode 100644 index 0000000000..34306ccc53 --- /dev/null +++ b/Zend/tests/hex_overflow_32bit.phpt @@ -0,0 +1,27 @@ +--TEST-- +testing integer overflow (32bit) +--SKIPIF-- +<?php if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?> +--FILE-- +<?php + +$doubles = array( + 0x1736123FFFAAA, + 0XFFFFFFFFFFFFFFFFFF, + 0xAAAAAAAAAAAAAAEEEEEEEEEBBB, + 0x66666666666666666777777, + ); + +foreach ($doubles as $d) { + $l = $d; + var_dump($l); +} + +echo "Done\n"; +?> +--EXPECTF-- +float(4083360297110%d) +float(4.7223664828%dE+21) +float(1.3521606402%dE+31) +float(1.9807040628%dE+27) +Done diff --git a/Zend/tests/oct_overflow_32bit.phpt b/Zend/tests/oct_overflow_32bit.phpt new file mode 100644 index 0000000000..77befbaa7a --- /dev/null +++ b/Zend/tests/oct_overflow_32bit.phpt @@ -0,0 +1,29 @@ +--TEST-- +testing integer overflow (32bit) +--SKIPIF-- +<?php if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?> +--FILE-- +<?php + +$doubles = array( + 076545676543223, + 032325463734, + 077777797777777, + 07777777777777977777777777, + 03333333333333382222222222222, + ); + +foreach ($doubles as $d) { + $l = (double)$d; + var_dump($l); +} + +echo "Done\n"; +?> +--EXPECTF-- +float(4308640384%d) +float(3545655%d) +float(262143) +float(549755813%d) +float(1884877076%d) +Done diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index bf76d9773c..ca0912323f 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1247,7 +1247,11 @@ NEWLINE ("\r"|"\n"|"\r\n") errno = 0; zendlval->value.lval = strtol(yytext, NULL, 0); if (errno == ERANGE) { /* Overflow */ - zendlval->value.dval = zend_strtod(yytext, NULL); + if (yytext[0] == '0') { /* octal overflow */ + zendlval->value.dval = zend_oct_strtod(yytext, NULL); + } else { + zendlval->value.dval = zend_strtod(yytext, NULL); + } zendlval->type = IS_DOUBLE; return T_DNUMBER; } diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c index 94d1383aa2..49b591da14 100644 --- a/Zend/zend_strtod.c +++ b/Zend/zend_strtod.c @@ -2604,6 +2604,34 @@ ZEND_API double zend_hex_strtod(const char *str, char **endptr) return value; } +ZEND_API double zend_oct_strtod(const char *str, char **endptr) +{ + const char *s = str; + char c; + double value = 0; + int any = 0; + + /* skip leading zero */ + s++; + + while ((c = *s++)) { + if (c > '7') { + /* break and return the current value if the number is not well-formed + * that's what Linux strtol() does + */ + break; + } + value = value * 8 + c - '0'; + any = 1; + } + + if (endptr != NULL) { + *endptr = (char *)(any ? s - 1 : str); + } + + return value; +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_strtod.h b/Zend/zend_strtod.h index 2dfe5a1a60..f4e066a58a 100644 --- a/Zend/zend_strtod.h +++ b/Zend/zend_strtod.h @@ -29,6 +29,7 @@ ZEND_API void zend_freedtoa(char *s); ZEND_API char * zend_dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve); ZEND_API double zend_strtod(const char *s00, char **se); ZEND_API double zend_hex_strtod(const char *str, char **endptr); +ZEND_API double zend_oct_strtod(const char *str, char **endptr); ZEND_API int zend_startup_strtod(void); ZEND_API int zend_shutdown_strtod(void); END_EXTERN_C() |