diff options
author | Stanislav Malyshev <stas@php.net> | 2016-10-10 23:42:50 -0700 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2016-10-10 23:42:50 -0700 |
commit | 8259130b6bc752968856b352c9e7f8e03a8c0a8e (patch) | |
tree | e015206451aa244627074afd7a8f5fe7c9643848 | |
parent | d946d102936525bc7dcd01f3827d0a6e0bb971b0 (diff) | |
download | php-git-8259130b6bc752968856b352c9e7f8e03a8c0a8e.tar.gz |
Fix for #73240 - Write out of bounds at number_format
-rw-r--r-- | ext/standard/math.c | 108 |
1 files changed, 60 insertions, 48 deletions
diff --git a/ext/standard/math.c b/ext/standard/math.c index 5ffeff7a18..8290b2044f 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -144,7 +144,7 @@ PHPAPI double _php_math_round(double value, int places, int mode) { if (!php_math_is_finite(value)) { return value; } - + places = places < INT_MIN+1 ? INT_MIN+1 : places; precision_places = 14 - php_intlog10abs(value); @@ -187,7 +187,7 @@ PHPAPI double _php_math_round(double value, int places, int mode) { /* round the temp value */ tmp_value = php_round_helper(tmp_value, mode); - + /* see if it makes sense to use simple division to round the value */ if (abs(places) < 23) { if (places > 0) { @@ -280,15 +280,15 @@ static double php_expm1(double x) /* {{{ proto int abs(int number) Return the absolute value of the number */ -PHP_FUNCTION(abs) +PHP_FUNCTION(abs) { zval **value; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) { return; } convert_scalar_to_number_ex(value); - + if (Z_TYPE_PP(value) == IS_DOUBLE) { RETURN_DOUBLE(fabs(Z_DVAL_PP(value))); } else if (Z_TYPE_PP(value) == IS_LONG) { @@ -300,14 +300,14 @@ PHP_FUNCTION(abs) } RETURN_FALSE; } -/* }}} */ +/* }}} */ /* {{{ proto float ceil(float number) Returns the next highest integer value of the number */ -PHP_FUNCTION(ceil) +PHP_FUNCTION(ceil) { zval **value; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) { return; } @@ -328,7 +328,7 @@ PHP_FUNCTION(ceil) PHP_FUNCTION(floor) { zval **value; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) { return; } @@ -353,7 +353,7 @@ PHP_FUNCTION(round) long precision = 0; long mode = PHP_ROUND_HALF_UP; double return_val; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|ll", &value, &precision, &mode) == FAILURE) { return; } @@ -410,7 +410,7 @@ PHP_FUNCTION(sin) PHP_FUNCTION(cos) { double num; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) { return; } @@ -540,7 +540,7 @@ PHP_FUNCTION(asinh) PHP_FUNCTION(acosh) { double num; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) { return; } @@ -639,7 +639,7 @@ PHP_FUNCTION(exp) /* {{{ proto float expm1(float number) Returns exp(number) - 1, computed in a way that accurate even when the value of number is close to zero */ /* - WARNING: this function is expermental: it could change its name or + WARNING: this function is expermental: it could change its name or disappear in the next version of PHP! */ PHP_FUNCTION(expm1) @@ -654,9 +654,9 @@ PHP_FUNCTION(expm1) /* }}} */ /* {{{ proto float log1p(float number) - Returns log(1 + number), computed in a way that accurate even when the value of number is close to zero */ + Returns log(1 + number), computed in a way that accurate even when the value of number is close to zero */ /* - WARNING: this function is expermental: it could change its name or + WARNING: this function is expermental: it could change its name or disappear in the next version of PHP! */ PHP_FUNCTION(log1p) @@ -675,7 +675,7 @@ PHP_FUNCTION(log1p) PHP_FUNCTION(log) { double num, base = 0; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|d", &num, &base) == FAILURE) { return; } @@ -683,7 +683,7 @@ PHP_FUNCTION(log) RETURN_DOUBLE(log(num)); } if (base <= 0.0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0"); RETURN_FALSE; } if (base == 1) { @@ -721,7 +721,7 @@ PHP_FUNCTION(sqrt) /* }}} */ /* {{{ proto float hypot(float num1, float num2) - Returns sqrt(num1*num1 + num2*num2) */ + Returns sqrt(num1*num1 + num2*num2) */ PHP_FUNCTION(hypot) { double num1, num2; @@ -783,12 +783,12 @@ PHPAPI long _php_math_basetolong(zval *arg, int base) for (i = Z_STRLEN_P(arg); i > 0; i--) { c = *s++; - + digit = (c >= '0' && c <= '9') ? c - '0' : (c >= 'A' && c <= 'Z') ? c - 'A' + 10 : (c >= 'a' && c <= 'z') ? c - 'a' + 10 : base; - + if (digit >= base) { continue; } @@ -832,23 +832,23 @@ PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret) cutoff = LONG_MAX / base; cutlim = LONG_MAX % base; - + for (i = Z_STRLEN_P(arg); i > 0; i--) { c = *s++; /* might not work for EBCDIC */ - if (c >= '0' && c <= '9') + if (c >= '0' && c <= '9') c -= '0'; - else if (c >= 'A' && c <= 'Z') + else if (c >= 'A' && c <= 'Z') c -= 'A' - 10; - else if (c >= 'a' && c <= 'z') + else if (c >= 'a' && c <= 'z') c -= 'a' - 10; else continue; if (c >= base) continue; - + switch (mode) { case 0: /* Integer */ if (num < cutoff || (num == cutoff && c <= cutlim)) { @@ -861,7 +861,7 @@ PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret) /* fall-through */ case 1: /* Float */ fnum = fnum * base + c; - } + } } if (mode == 1) { @@ -937,9 +937,9 @@ PHPAPI char * _php_math_zvaltobase(zval *arg, int base TSRMLS_DC) return estrndup(ptr, end - ptr); } - + return _php_math_longtobase(arg, base); -} +} /* }}} */ /* {{{ proto int bindec(string binary_number) @@ -947,7 +947,7 @@ PHPAPI char * _php_math_zvaltobase(zval *arg, int base TSRMLS_DC) PHP_FUNCTION(bindec) { zval **arg; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) { return; } @@ -963,7 +963,7 @@ PHP_FUNCTION(bindec) PHP_FUNCTION(hexdec) { zval **arg; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) { return; } @@ -979,7 +979,7 @@ PHP_FUNCTION(hexdec) PHP_FUNCTION(octdec) { zval **arg; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) { return; } @@ -1050,7 +1050,7 @@ PHP_FUNCTION(base_convert) return; } convert_to_string_ex(number); - + if (frombase < 2 || frombase > 36) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `from base' (%ld)", frombase); RETURN_FALSE; @@ -1065,10 +1065,10 @@ PHP_FUNCTION(base_convert) } result = _php_math_zvaltobase(&temp, tobase TSRMLS_CC); RETVAL_STRING(result, 0); -} +} /* }}} */ -/* {{{ _php_math_number_format +/* {{{ _php_math_number_format */ PHPAPI char *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep) { @@ -1077,13 +1077,13 @@ PHPAPI char *_php_math_number_format(double d, int dec, char dec_point, char tho static char *_php_math_number_format_ex_len(double d, int dec, char *dec_point, size_t dec_point_len, char *thousand_sep, size_t thousand_sep_len, - int *result_len) + size_t *result_len) { char *tmpbuf = NULL, *resbuf; char *s, *t; /* source, target */ char *dp; - int integral; - int tmplen, reslen=0; + size_t integral; + size_t tmplen, reslen=0; int count=0; int is_negative=0; @@ -1122,15 +1122,23 @@ static char *_php_math_number_format_ex_len(double d, int dec, char *dec_point, /* allow for thousand separators */ if (thousand_sep) { + if (integral + thousand_sep_len * ((integral-1) / 3) < integral) { + /* overflow */ + php_error_docref(NULL TSRMLS_CC, E_ERROR, "String overflow"); + } integral += thousand_sep_len * ((integral-1) / 3); } - + reslen = integral; - + if (dec) { reslen += dec; if (dec_point) { + if (reslen + dec_point < dec_point) { + /* overflow */ + php_error_docref(NULL TSRMLS_CC, E_ERROR, "String overflow"); + } reslen += dec_point_len; } } @@ -1156,7 +1164,7 @@ static char *_php_math_number_format_ex_len(double d, int dec, char *dec_point, while (topad--) { *t-- = '0'; } - + if (dp) { s -= declen + 1; /* +1 to skip the point */ t -= declen; @@ -1188,7 +1196,7 @@ static char *_php_math_number_format_ex_len(double d, int dec, char *dec_point, } efree(tmpbuf); - + if (result_len) { *result_len = reslen; } @@ -1213,17 +1221,21 @@ PHP_FUNCTION(number_format) char *thousand_sep = NULL, *dec_point = NULL; char thousand_sep_chr = ',', dec_point_chr = '.'; int thousand_sep_len = 0, dec_point_len = 0; - + char *formatted; + size_t formatted_len; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|ls!s!", &num, &dec, &dec_point, &dec_point_len, &thousand_sep, &thousand_sep_len) == FAILURE) { return; } switch(ZEND_NUM_ARGS()) { case 1: - RETURN_STRING(_php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr), 0); + formatted = _php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr); + formatted_len = strlen(formatted); break; case 2: - RETURN_STRING(_php_math_number_format(num, dec, dec_point_chr, thousand_sep_chr), 0); + formatted = _php_math_number_format(num, dec, dec_point_chr, thousand_sep_chr); + formatted_len = strlen(formatted); break; case 4: if (dec_point == NULL) { @@ -1236,15 +1248,15 @@ PHP_FUNCTION(number_format) thousand_sep_len = 1; } - Z_TYPE_P(return_value) = IS_STRING; - Z_STRVAL_P(return_value) = _php_math_number_format_ex_len(num, dec, + formatted = _php_math_number_format_ex_len(num, dec, dec_point, dec_point_len, thousand_sep, thousand_sep_len, - &Z_STRLEN_P(return_value)); + &formatted_len); break; default: WRONG_PARAM_COUNT; - break; + return; } + RETVAL_STRINGL_CHECK(formatted, formatted_len, 0); } /* }}} */ |