Skip to content

Commit 0022353

Browse files
committed
made scale argument of bcmath functions non-negative integer
1 parent 77ee4e6 commit 0022353

File tree

6 files changed

+176
-28
lines changed

6 files changed

+176
-28
lines changed

ext/bcmath/bcmath.c

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ zend_module_entry bcmath_module_entry = {
4545
PHP_BCMATH_VERSION,
4646
PHP_MODULE_GLOBALS(bcmath),
4747
PHP_GINIT(bcmath),
48-
PHP_GSHUTDOWN(bcmath),
48+
PHP_GSHUTDOWN(bcmath),
4949
NULL,
5050
STANDARD_MODULE_PROPERTIES_EX
5151
};
@@ -57,9 +57,32 @@ ZEND_TSRMLS_CACHE_DEFINE()
5757
ZEND_GET_MODULE(bcmath)
5858
#endif
5959

60+
ZEND_INI_MH(OnUpdateScale)
61+
{
62+
int *p;
63+
zend_long tmp;
64+
#ifndef ZTS
65+
char *base = (char *) mh_arg2;
66+
#else
67+
char *base;
68+
69+
base = (char *) ts_resource(*((int *) mh_arg2));
70+
#endif
71+
72+
tmp = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
73+
if (tmp < 0 || tmp > INT_MAX) {
74+
return FAILURE;
75+
}
76+
77+
p = (int *) (base+(size_t) mh_arg1);
78+
*p = (int) tmp;
79+
80+
return SUCCESS;
81+
}
82+
6083
/* {{{ PHP_INI */
6184
PHP_INI_BEGIN()
62-
STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
85+
STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateScale, bc_precision, zend_bcmath_globals, bcmath_globals)
6386
PHP_INI_END()
6487
/* }}} */
6588

@@ -152,7 +175,11 @@ PHP_FUNCTION(bcadd)
152175
ZEND_PARSE_PARAMETERS_END();
153176

154177
if (ZEND_NUM_ARGS() == 3) {
155-
scale = (int) (scale_param < 0 ? 0 : scale_param);
178+
if (scale_param < 0 || scale_param > INT_MAX) {
179+
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
180+
RETURN_THROWS();
181+
}
182+
scale = (int) scale_param;
156183
}
157184

158185
bc_init_num(&first);
@@ -187,7 +214,11 @@ PHP_FUNCTION(bcsub)
187214
ZEND_PARSE_PARAMETERS_END();
188215

189216
if (ZEND_NUM_ARGS() == 3) {
190-
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
217+
if (scale_param < 0 || scale_param > INT_MAX) {
218+
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
219+
RETURN_THROWS();
220+
}
221+
scale = (int) scale_param;
191222
}
192223

193224
bc_init_num(&first);
@@ -222,7 +253,11 @@ PHP_FUNCTION(bcmul)
222253
ZEND_PARSE_PARAMETERS_END();
223254

224255
if (ZEND_NUM_ARGS() == 3) {
225-
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
256+
if (scale_param < 0 || scale_param > INT_MAX) {
257+
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
258+
RETURN_THROWS();
259+
}
260+
scale = (int) scale_param;
226261
}
227262

228263
bc_init_num(&first);
@@ -257,7 +292,11 @@ PHP_FUNCTION(bcdiv)
257292
ZEND_PARSE_PARAMETERS_END();
258293

259294
if (ZEND_NUM_ARGS() == 3) {
260-
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
295+
if (scale_param < 0 || scale_param > INT_MAX) {
296+
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
297+
RETURN_THROWS();
298+
}
299+
scale = (int) scale_param;
261300
}
262301

263302
bc_init_num(&first);
@@ -299,7 +338,11 @@ PHP_FUNCTION(bcmod)
299338
ZEND_PARSE_PARAMETERS_END();
300339

301340
if (ZEND_NUM_ARGS() == 3) {
302-
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
341+
if (scale_param < 0 || scale_param > INT_MAX) {
342+
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
343+
RETURN_THROWS();
344+
}
345+
scale = (int) scale_param;
303346
}
304347

305348
bc_init_num(&first);
@@ -329,18 +372,26 @@ PHP_FUNCTION(bcmod)
329372
PHP_FUNCTION(bcpowmod)
330373
{
331374
zend_string *left, *right, *modulus;
375+
zend_long scale_param = 0;
332376
bc_num first, second, mod, result;
333-
zend_long scale = BCG(bc_precision);
334-
int scale_int;
377+
int scale = (int)BCG(bc_precision);
335378

336379
ZEND_PARSE_PARAMETERS_START(3, 4)
337380
Z_PARAM_STR(left)
338381
Z_PARAM_STR(right)
339382
Z_PARAM_STR(modulus)
340383
Z_PARAM_OPTIONAL
341-
Z_PARAM_LONG(scale)
384+
Z_PARAM_LONG(scale_param)
342385
ZEND_PARSE_PARAMETERS_END();
343386

387+
if (ZEND_NUM_ARGS() == 4) {
388+
if (scale_param < 0 || scale_param > INT_MAX) {
389+
zend_argument_value_error(4, "must be between 0 and %d", INT_MAX);
390+
RETURN_THROWS();
391+
}
392+
scale = (int) scale_param;
393+
}
394+
344395
bc_init_num(&first);
345396
bc_init_num(&second);
346397
bc_init_num(&mod);
@@ -349,10 +400,8 @@ PHP_FUNCTION(bcpowmod)
349400
php_str2num(&second, ZSTR_VAL(right));
350401
php_str2num(&mod, ZSTR_VAL(modulus));
351402

352-
scale_int = (int) ((int)scale < 0 ? 0 : scale);
353-
354-
if (bc_raisemod(first, second, mod, &result, scale_int) != -1) {
355-
RETVAL_STR(bc_num2str_ex(result, scale_int));
403+
if (bc_raisemod(first, second, mod, &result, scale) != -1) {
404+
RETVAL_STR(bc_num2str_ex(result, scale));
356405
} else {
357406
RETVAL_FALSE;
358407
}
@@ -382,7 +431,11 @@ PHP_FUNCTION(bcpow)
382431
ZEND_PARSE_PARAMETERS_END();
383432

384433
if (ZEND_NUM_ARGS() == 3) {
385-
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
434+
if (scale_param < 0 || scale_param > INT_MAX) {
435+
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
436+
RETURN_THROWS();
437+
}
438+
scale = (int) scale_param;
386439
}
387440

388441
bc_init_num(&first);
@@ -416,7 +469,11 @@ PHP_FUNCTION(bcsqrt)
416469
ZEND_PARSE_PARAMETERS_END();
417470

418471
if (ZEND_NUM_ARGS() == 2) {
419-
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
472+
if (scale_param < 0 || scale_param > INT_MAX) {
473+
zend_argument_value_error(2, "must be between 0 and %d", INT_MAX);
474+
RETURN_THROWS();
475+
}
476+
scale = (int) scale_param;
420477
}
421478

422479
bc_init_num(&result);
@@ -450,7 +507,11 @@ PHP_FUNCTION(bccomp)
450507
ZEND_PARSE_PARAMETERS_END();
451508

452509
if (ZEND_NUM_ARGS() == 3) {
453-
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
510+
if (scale_param < 0 || scale_param > INT_MAX) {
511+
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
512+
RETURN_THROWS();
513+
}
514+
scale = (int) scale_param;
454515
}
455516

456517
bc_init_num(&first);
@@ -460,7 +521,7 @@ PHP_FUNCTION(bccomp)
460521
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
461522
}
462523
if (!bc_str2num(&second, ZSTR_VAL(right), scale)) {
463-
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
524+
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
464525
}
465526
RETVAL_LONG(bc_compare(first, second));
466527

@@ -484,7 +545,11 @@ PHP_FUNCTION(bcscale)
484545
old_scale = BCG(bc_precision);
485546

486547
if (ZEND_NUM_ARGS() == 1) {
487-
BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
548+
if (new_scale < 0 || new_scale > INT_MAX) {
549+
zend_argument_value_error(1, "must be between 0 and %d", INT_MAX);
550+
RETURN_THROWS();
551+
}
552+
BCG(bc_precision) = (int) new_scale;
488553
}
489554

490555
RETURN_LONG(old_scale);

ext/bcmath/php_bcmath.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ ZEND_BEGIN_MODULE_GLOBALS(bcmath)
3333
bc_num _zero_;
3434
bc_num _one_;
3535
bc_num _two_;
36-
zend_long bc_precision;
36+
int bc_precision;
3737
ZEND_END_MODULE_GLOBALS(bcmath)
3838

3939
#if defined(ZTS) && defined(COMPILE_DL_BCMATH)
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
--TEST--
2-
bcscale() with negative argument
2+
bcscale() fails with negative argument
33
--SKIPIF--
44
<?php if(!extension_loaded("bcmath")) print "skip"; ?>
55
--INI--
66
bcmath.scale=0
77
--FILE--
88
<?php
9-
bcscale(-4);
109
echo bcdiv("20.56", "4");
10+
try {
11+
bcscale(-4);
12+
} catch (\ValueError $e) {
13+
echo \PHP_EOL . $e->getMessage() . \PHP_EOL;
14+
}
1115
?>
1216
--EXPECT--
1317
5
18+
bcscale(): Argument #1 ($scale) must be between 0 and 2147483647

ext/bcmath/tests/bug60377.phpt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ bcscale related problem on 64bits platforms
55
if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
66
--FILE--
77
<?php
8-
$var48 = bcscale(634314234334311);
8+
try {
9+
$var48 = bcscale(634314234334311);
10+
} catch (\ValueError $e) {
11+
echo $e->getMessage() . \PHP_EOL;
12+
}
913
$var67 = bcsqrt(0);
1014
$var414 = bcadd(0,-1,10);
11-
die('ALIVE');
1215
?>
16+
1317
--EXPECT--
14-
ALIVE
18+
bcscale(): Argument #1 ($scale) must be between 0 and 2147483647

ext/bcmath/tests/bug72093.phpt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
--TEST--
2-
Bug 72093: bcpowmod accepts negative scale and corrupts _one_ definition
2+
Bug 72093: bcpowmod fails on negative scale and corrupts _one_ definition
33
--SKIPIF--
44
<?php
55
if(!extension_loaded("bcmath")) print "skip";
66
?>
77
--FILE--
88
<?php
9-
var_dump(bcpowmod(1, 0, 128, -200));
9+
try {
10+
var_dump(bcpowmod(1, 0, 128, -200));
11+
} catch (\ValueError $e) {
12+
echo $e->getMessage() . \PHP_EOL;
13+
}
1014
var_dump(bcpowmod(1, 1.2, 1, 1));
1115
?>
1216
--EXPECTF--
13-
string(1) "1"
17+
bcpowmod(): Argument #4 ($scale) must be between 0 and 2147483647
1418

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

ext/bcmath/tests/negative_scale.phpt

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
--TEST--
2+
all errors on negative scale
3+
--SKIPIF--
4+
<?php if(!extension_loaded("bcmath")) print "skip"; ?>
5+
--INI--
6+
bcmath.scale=0
7+
--FILE--
8+
<?php
9+
try {
10+
bcadd('1','2',-1);
11+
} catch (\ValueError $e) {
12+
echo $e->getMessage() . \PHP_EOL;
13+
}
14+
try {
15+
bcsub('1','2',-1);
16+
} catch (\ValueError $e) {
17+
echo $e->getMessage() . \PHP_EOL;
18+
}
19+
try {
20+
bcmul('1','2',-1);
21+
} catch (\ValueError $e) {
22+
echo $e->getMessage() . \PHP_EOL;
23+
}
24+
try {
25+
bcdiv('1','2',-1);
26+
} catch (\ValueError $e) {
27+
echo $e->getMessage() . \PHP_EOL;
28+
}
29+
try {
30+
bcmod('1','2',-1);
31+
} catch (\ValueError $e) {
32+
echo $e->getMessage() . \PHP_EOL;
33+
}
34+
try {
35+
bcpowmod('1', '2', '3', -9);
36+
} catch (\ValueError $e) {
37+
echo $e->getMessage() . \PHP_EOL;
38+
}
39+
try {
40+
bcpow('1', '2', -1);
41+
} catch (\ValueError $e) {
42+
echo $e->getMessage() . \PHP_EOL;
43+
}
44+
try {
45+
bcsqrt('9', -1);
46+
} catch (\ValueError $e) {
47+
echo $e->getMessage() . \PHP_EOL;
48+
}
49+
try {
50+
bccomp('1', '2', -1);
51+
} catch (\ValueError $e) {
52+
echo $e->getMessage() . \PHP_EOL;
53+
}
54+
try {
55+
bcscale(-1);
56+
} catch (\ValueError $e) {
57+
echo $e->getMessage() . \PHP_EOL;
58+
}
59+
?>
60+
--EXPECT--
61+
bcadd(): Argument #3 ($scale) must be between 0 and 2147483647
62+
bcsub(): Argument #3 ($scale) must be between 0 and 2147483647
63+
bcmul(): Argument #3 ($scale) must be between 0 and 2147483647
64+
bcdiv(): Argument #3 ($scale) must be between 0 and 2147483647
65+
bcmod(): Argument #3 ($scale) must be between 0 and 2147483647
66+
bcpowmod(): Argument #4 ($scale) must be between 0 and 2147483647
67+
bcpow(): Argument #3 ($scale) must be between 0 and 2147483647
68+
bcsqrt(): Argument #2 ($scale) must be between 0 and 2147483647
69+
bccomp(): Argument #3 ($scale) must be between 0 and 2147483647
70+
bcscale(): Argument #1 ($scale) must be between 0 and 2147483647

0 commit comments

Comments
 (0)