From: Antony Dovgal Date: Thu, 19 Apr 2007 11:24:48 +0000 (+0000) Subject: fix #41118 (PHP does not handle overflow of octal integers) X-Git-Tag: RELEASE_1_2_0~269 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=66be3528179d2b9cb23ba35d8869aac4f058ffa1;p=php fix #41118 (PHP does not handle overflow of octal integers) MFB a small part of optimization patch applied only to 5_2 --- 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-- + +--FILE-- + +--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-- + +--FILE-- + +--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 0fb4b65c89..b992324dbb 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1865,36 +1865,45 @@ NEWLINE ("\r"|"\n"|"\r\n") {LNUM} { - errno = 0; - Z_LVAL_P(zendlval) = strtol(yytext, NULL, 0); - if (errno == ERANGE) { /* overflow */ - Z_DVAL_P(zendlval) = zend_strtod(yytext, NULL); - Z_TYPE_P(zendlval) = IS_DOUBLE; - return T_DNUMBER; - } else { - Z_TYPE_P(zendlval) = IS_LONG; - return T_LNUMBER; - } + if (yyleng < MAX_LENGTH_OF_LONG - 1) { /* Won't overflow */ + zendlval->value.lval = strtol(yytext, NULL, 0); + } else { + errno = 0; + zendlval->value.lval = strtol(yytext, NULL, 0); + if (errno == ERANGE) { /* Overflow */ + 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; + } + } + + zendlval->type = IS_LONG; + return T_LNUMBER; } {HNUM} { - errno = 0; - Z_LVAL_P(zendlval) = strtoul(yytext, NULL, 16); - if (errno == ERANGE) { /* overflow */ - /* not trying strtod - it returns trash on 0x-es */ - Z_LVAL_P(zendlval) = LONG_MAX; /* maximal long */ - zend_error(E_NOTICE,"Hex number is too big: %s", yytext); - } else { - if (Z_LVAL_P(zendlval) < 0) { - /* maintain consistency with the old way */ - Z_DVAL_P(zendlval) = (unsigned long) Z_LVAL_P(zendlval); - Z_TYPE_P(zendlval) = IS_DOUBLE; - return T_DNUMBER; - } - Z_TYPE_P(zendlval) = IS_LONG; - } - Z_TYPE_P(zendlval) = IS_LONG; - return T_LNUMBER; + char *hex = yytext + 2; /* Skip "0x" */ + int len = yyleng - 2; + + /* Skip any leading 0s */ + while (*hex == '0') { + hex++; + len--; + } + + if (len < SIZEOF_LONG * 2 || (len == SIZEOF_LONG * 2 && *hex <= '7')) { + zendlval->value.lval = strtol(hex, NULL, 16); + zendlval->type = IS_LONG; + return T_LNUMBER; + } else { + zendlval->value.dval = zend_hex_strtod(hex, NULL); + zendlval->type = IS_DOUBLE; + return T_DNUMBER; + } } {LNUM}|{HNUM} { /* treat numbers (almost) as strings inside encapsulated strings */ diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 90025f57a3..44c4b6a850 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -36,7 +36,16 @@ #include "ext/bcmath/libbcmath/src/bcmath.h" #endif +#if SIZEOF_LONG == 4 +#define MAX_LENGTH_OF_LONG 11 +static const char long_min_digits[] = "2147483648"; +#elif SIZEOF_LONG == 8 #define MAX_LENGTH_OF_LONG 20 +static const char long_min_digits[] = "9223372036854775808"; +#else +#error "Unknown SIZEOF_LONG" +#endif + #define MAX_LENGTH_OF_DOUBLE 32 BEGIN_EXTERN_C() diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c index 23dd743ef9..227d9667eb 100644 --- a/Zend/zend_strtod.c +++ b/Zend/zend_strtod.c @@ -2671,6 +2671,69 @@ ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */ } /* }}} */ +ZEND_API double zend_hex_strtod(const char *str, char **endptr) /* {{{ */ +{ + const char *s = str; + char c; + int any = 0; + double value = 0; + + if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) { + s += 2; + } + + while ((c = *s++)) { + if (c >= '0' && c <= '9') { + c -= '0'; + } else if (c >= 'A' && c <= 'F') { + c -= 'A' - 10; + } else if (c >= 'a' && c <= 'f') { + c -= 'a' - 10; + } else { + break; + } + + any = 1; + value = value * 16 + c; + } + + if (endptr != NULL) { + *endptr = (char *)(any ? s - 1 : str); + } + + 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 7837a6311c..329c19f68a 100644 --- a/Zend/zend_strtod.h +++ b/Zend/zend_strtod.h @@ -29,6 +29,8 @@ 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_u_strtod(const UChar *nptr, UChar **endptr); +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()