--- /dev/null
+--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
--- /dev/null
+--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
<ST_IN_SCRIPTING>{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;
}
<ST_IN_SCRIPTING>{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;
+ }
}
<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>{LNUM}|{HNUM} { /* treat numbers (almost) as strings inside encapsulated strings */
#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()
}
/* }}} */
+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
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()