Skip to content

made scale argument of bcmath functions non-negative integer #5455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 85 additions & 27 deletions ext/bcmath/bcmath.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ zend_module_entry bcmath_module_entry = {
PHP_BCMATH_VERSION,
PHP_MODULE_GLOBALS(bcmath),
PHP_GINIT(bcmath),
PHP_GSHUTDOWN(bcmath),
PHP_GSHUTDOWN(bcmath),
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
Expand All @@ -57,9 +57,25 @@ ZEND_TSRMLS_CACHE_DEFINE()
ZEND_GET_MODULE(bcmath)
#endif

ZEND_INI_MH(OnUpdateScale)
{
int *p;
zend_long tmp;

tmp = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
if (tmp < 0 || tmp > INT_MAX) {
return FAILURE;
}

p = (int *) ZEND_INI_GET_ADDR();
*p = (int) tmp;

return SUCCESS;
}

/* {{{ PHP_INI */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateScale, bc_precision, zend_bcmath_globals, bcmath_globals)
PHP_INI_END()
/* }}} */

Expand Down Expand Up @@ -142,7 +158,7 @@ PHP_FUNCTION(bcadd)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Expand All @@ -152,7 +168,11 @@ PHP_FUNCTION(bcadd)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 3) {
scale = (int) (scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
Expand All @@ -177,7 +197,7 @@ PHP_FUNCTION(bcsub)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Expand All @@ -187,7 +207,11 @@ PHP_FUNCTION(bcsub)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
Expand All @@ -212,7 +236,7 @@ PHP_FUNCTION(bcmul)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Expand All @@ -222,7 +246,11 @@ PHP_FUNCTION(bcmul)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
Expand All @@ -247,7 +275,7 @@ PHP_FUNCTION(bcdiv)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Expand All @@ -257,7 +285,11 @@ PHP_FUNCTION(bcdiv)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
Expand Down Expand Up @@ -289,7 +321,7 @@ PHP_FUNCTION(bcmod)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Expand All @@ -299,7 +331,11 @@ PHP_FUNCTION(bcmod)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
Expand Down Expand Up @@ -329,18 +365,26 @@ PHP_FUNCTION(bcmod)
PHP_FUNCTION(bcpowmod)
{
zend_string *left, *right, *modulus;
zend_long scale_param = 0;
bc_num first, second, mod, result;
zend_long scale = BCG(bc_precision);
int scale_int;
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(3, 4)
Z_PARAM_STR(left)
Z_PARAM_STR(right)
Z_PARAM_STR(modulus)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(scale)
Z_PARAM_LONG(scale_param)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 4) {
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(4, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&mod);
Expand All @@ -349,10 +393,8 @@ PHP_FUNCTION(bcpowmod)
php_str2num(&second, ZSTR_VAL(right));
php_str2num(&mod, ZSTR_VAL(modulus));

scale_int = (int) ((int)scale < 0 ? 0 : scale);

if (bc_raisemod(first, second, mod, &result, scale_int) != -1) {
RETVAL_STR(bc_num2str_ex(result, scale_int));
if (bc_raisemod(first, second, mod, &result, scale) != -1) {
RETVAL_STR(bc_num2str_ex(result, scale));
} else {
RETVAL_FALSE;
}
Expand All @@ -372,7 +414,7 @@ PHP_FUNCTION(bcpow)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Expand All @@ -382,7 +424,11 @@ PHP_FUNCTION(bcpow)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
Expand All @@ -407,7 +453,7 @@ PHP_FUNCTION(bcsqrt)
zend_string *left;
zend_long scale_param = 0;
bc_num result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(left)
Expand All @@ -416,7 +462,11 @@ PHP_FUNCTION(bcsqrt)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 2) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(2, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&result);
Expand All @@ -440,7 +490,7 @@ PHP_FUNCTION(bccomp)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Expand All @@ -450,7 +500,11 @@ PHP_FUNCTION(bccomp)
ZEND_PARSE_PARAMETERS_END();

if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}

bc_init_num(&first);
Expand All @@ -460,7 +514,7 @@ PHP_FUNCTION(bccomp)
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
}
if (!bc_str2num(&second, ZSTR_VAL(right), scale)) {
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
}
RETVAL_LONG(bc_compare(first, second));

Expand All @@ -484,7 +538,11 @@ PHP_FUNCTION(bcscale)
old_scale = BCG(bc_precision);

if (ZEND_NUM_ARGS() == 1) {
BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
if (new_scale < 0 || new_scale > INT_MAX) {
zend_argument_value_error(1, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
BCG(bc_precision) = (int) new_scale;
}

RETURN_LONG(old_scale);
Expand Down
2 changes: 1 addition & 1 deletion ext/bcmath/php_bcmath.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ZEND_BEGIN_MODULE_GLOBALS(bcmath)
bc_num _zero_;
bc_num _one_;
bc_num _two_;
zend_long bc_precision;
int bc_precision;
ZEND_END_MODULE_GLOBALS(bcmath)

#if defined(ZTS) && defined(COMPILE_DL_BCMATH)
Expand Down
9 changes: 7 additions & 2 deletions ext/bcmath/tests/bcscale_variation001.phpt
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
--TEST--
bcscale() with negative argument
bcscale() fails with negative argument
--SKIPIF--
<?php if(!extension_loaded("bcmath")) print "skip"; ?>
--INI--
bcmath.scale=0
--FILE--
<?php
bcscale(-4);
echo bcdiv("20.56", "4");
try {
bcscale(-4);
} catch (\ValueError $e) {
echo \PHP_EOL . $e->getMessage() . \PHP_EOL;
}
?>
--EXPECT--
5
bcscale(): Argument #1 ($scale) must be between 0 and 2147483647
10 changes: 7 additions & 3 deletions ext/bcmath/tests/bug60377.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ bcscale related problem on 64bits platforms
if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
$var48 = bcscale(634314234334311);
try {
$var48 = bcscale(634314234334311);
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
$var67 = bcsqrt(0);
$var414 = bcadd(0,-1,10);
die('ALIVE');
?>

--EXPECT--
ALIVE
bcscale(): Argument #1 ($scale) must be between 0 and 2147483647
10 changes: 7 additions & 3 deletions ext/bcmath/tests/bug72093.phpt
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
--TEST--
Bug 72093: bcpowmod accepts negative scale and corrupts _one_ definition
Bug 72093: bcpowmod fails on negative scale and corrupts _one_ definition
--SKIPIF--
<?php
if(!extension_loaded("bcmath")) print "skip";
?>
--FILE--
<?php
var_dump(bcpowmod(1, 0, 128, -200));
try {
var_dump(bcpowmod(1, 0, 128, -200));
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump(bcpowmod(1, 1.2, 1, 1));
?>
--EXPECTF--
string(1) "1"
bcpowmod(): Argument #4 ($scale) must be between 0 and 2147483647

Warning: bcpowmod(): Non-zero scale in exponent in %s on line %d
string(3) "0.0"
Loading