summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2016-10-10 23:42:50 -0700
committerStanislav Malyshev <stas@php.net>2016-10-10 23:42:50 -0700
commit8259130b6bc752968856b352c9e7f8e03a8c0a8e (patch)
treee015206451aa244627074afd7a8f5fe7c9643848
parentd946d102936525bc7dcd01f3827d0a6e0bb971b0 (diff)
downloadphp-git-8259130b6bc752968856b352c9e7f8e03a8c0a8e.tar.gz
Fix for #73240 - Write out of bounds at number_format
-rw-r--r--ext/standard/math.c108
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);
}
/* }}} */