Skip to content

Commit 373c7d1

Browse files
committed
BCMath operator overloading issues
1 parent 702fb31 commit 373c7d1

File tree

5 files changed

+184
-21
lines changed

5 files changed

+184
-21
lines changed

ext/bcmath/bcmath.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ static zend_result bcmath_number_parse_num(zval *zv, zend_object **obj, zend_str
11751175

11761176
case IS_NULL:
11771177
*lval = 0;
1178-
return SUCCESS;
1178+
return FAILURE;
11791179

11801180
default:
11811181
return zend_parse_arg_str_or_long_slow(zv, str, lval, 1 /* dummy */) ? SUCCESS : FAILURE;
@@ -1234,9 +1234,12 @@ static zend_result bcmath_number_do_operation(uint8_t opcode, zval *ret_val, zva
12341234
bc_num n2 = NULL;
12351235
size_t n1_full_scale;
12361236
size_t n2_full_scale;
1237-
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE ||
1238-
bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) {
1239-
zend_value_error("Number is not well-formed");
1237+
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE)) {
1238+
zend_value_error("Left string operand cannot be converted to BcMath\\Number");
1239+
goto fail;
1240+
}
1241+
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) {
1242+
zend_value_error("Right string operand cannot be converted to BcMath\\Number");
12401243
goto fail;
12411244
}
12421245

@@ -1317,39 +1320,39 @@ static int bcmath_number_compare(zval *op1, zval *op2)
13171320
bc_num n1 = NULL;
13181321
bc_num n2 = NULL;
13191322

1323+
int ret = ZEND_UNCOMPARABLE;
1324+
13201325
if (UNEXPECTED(bcmath_number_parse_num(op1, &obj1, &str1, &lval1) == FAILURE)) {
1321-
goto fallback;
1326+
goto failure;
13221327
}
13231328

13241329
if (UNEXPECTED(bcmath_number_parse_num(op2, &obj2, &str2, &lval2) == FAILURE)) {
1325-
goto fallback;
1330+
goto failure;
13261331
}
13271332

13281333
size_t n1_full_scale;
13291334
size_t n2_full_scale;
13301335
if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE ||
13311336
bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) {
1332-
goto fallback;
1337+
goto failure;
13331338
}
13341339

13351340
if (UNEXPECTED(CHECK_SCALE_OVERFLOW(n1_full_scale) || CHECK_SCALE_OVERFLOW(n2_full_scale))) {
13361341
zend_value_error("scale must be between 0 and %d", INT_MAX);
1337-
goto fallback;
1342+
goto failure;
13381343
}
13391344

1340-
bcmath_compare_result ret = bc_compare(n1, n2, MAX(n1->n_scale, n2->n_scale));
1345+
ret = bc_compare(n1, n2, MAX(n1->n_scale, n2->n_scale));
13411346

1347+
failure:
13421348
if (Z_TYPE_P(op1) != IS_OBJECT) {
13431349
bc_free_num(&n1);
13441350
}
13451351
if (Z_TYPE_P(op2) != IS_OBJECT) {
13461352
bc_free_num(&n2);
13471353
}
13481354

1349-
return (int) ret;
1350-
1351-
fallback:
1352-
return zend_std_compare_objects(op1, op2);
1355+
return ret;
13531356
}
13541357

13551358
#define BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(dest_obj, ce, dest_str, dest_long) \

ext/bcmath/tests/number/operators/calc_non_numeric_string.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ try {
4343
}
4444
?>
4545
--EXPECT--
46-
Number is not well-formed
47-
Number is not well-formed
48-
Number is not well-formed
49-
Number is not well-formed
50-
Number is not well-formed
51-
Number is not well-formed
46+
Right string operand cannot be converted to BcMath\Number
47+
Right string operand cannot be converted to BcMath\Number
48+
Right string operand cannot be converted to BcMath\Number
49+
Right string operand cannot be converted to BcMath\Number
50+
Right string operand cannot be converted to BcMath\Number
51+
Right string operand cannot be converted to BcMath\Number
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
BcMath\Number calc undefined var by operator
3+
--EXTENSIONS--
4+
bcmath
5+
--FILE--
6+
<?php
7+
$num = new BcMath\Number(100);
8+
9+
try {
10+
$num + null;
11+
} catch (Error $e) {
12+
echo $e->getMessage() . "\n";
13+
}
14+
15+
try {
16+
$num - null;
17+
} catch (Error $e) {
18+
echo $e->getMessage() . "\n";
19+
}
20+
21+
try {
22+
$num * null;
23+
} catch (Error $e) {
24+
echo $e->getMessage() . "\n";
25+
}
26+
27+
try {
28+
$num / null;
29+
} catch (Error $e) {
30+
echo $e->getMessage() . "\n";
31+
}
32+
33+
try {
34+
$num % null;
35+
} catch (Error $e) {
36+
echo $e->getMessage() . "\n";
37+
}
38+
39+
try {
40+
$num ** null;
41+
} catch (Error $e) {
42+
echo $e->getMessage() . "\n";
43+
}
44+
?>
45+
--EXPECT--
46+
Unsupported operand types: BcMath\Number + null
47+
Unsupported operand types: BcMath\Number - null
48+
Unsupported operand types: BcMath\Number * null
49+
Unsupported operand types: BcMath\Number / null
50+
Unsupported operand types: BcMath\Number % null
51+
Unsupported operand types: BcMath\Number ** null

ext/bcmath/tests/number/operators/calc_undef.phpt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,19 @@ try {
4444
?>
4545
--EXPECTF--
4646
Warning: Undefined variable $undef in %s
47+
Unsupported operand types: BcMath\Number + null
4748

4849
Warning: Undefined variable $undef in %s
50+
Unsupported operand types: BcMath\Number - null
4951

5052
Warning: Undefined variable $undef in %s
53+
Unsupported operand types: BcMath\Number * null
5154

5255
Warning: Undefined variable $undef in %s
53-
Division by zero
56+
Unsupported operand types: BcMath\Number / null
5457

5558
Warning: Undefined variable $undef in %s
56-
Modulo by zero
59+
Unsupported operand types: BcMath\Number % null
5760

5861
Warning: Undefined variable $undef in %s
62+
Unsupported operand types: BcMath\Number ** null
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
--TEST--
2+
BcMath\Number compare by operator with non-sense
3+
--EXTENSIONS--
4+
bcmath
5+
--FILE--
6+
<?php
7+
8+
$values2 = [
9+
[null, 'null'],
10+
['string', 'string'],
11+
[new stdClass(), 'object'],
12+
[[], 'array'],
13+
[STDERR, 'resource'],
14+
];
15+
16+
$value1 = new BcMath\Number('100.0000');
17+
18+
foreach ($values2 as [$value2, $type2]) {
19+
echo "========== with {$type2} ==========\n";
20+
echo "{$value1} > {$type2}: " . ($value1 > $value2 ? 'true' : 'false') . "\n";
21+
echo "{$value1} >= {$type2}: " . ($value1 >= $value2 ? 'true' : 'false') . "\n";
22+
echo "{$value1} == {$type2}: " . ($value1 == $value2 ? 'true' : 'false') . "\n";
23+
echo "{$value1} <= {$type2}: " . ($value1 <= $value2 ? 'true' : 'false') . "\n";
24+
echo "{$value1} < {$type2}: " . ($value1 < $value2 ? 'true' : 'false') . "\n";
25+
26+
echo "\ninversion\n";
27+
echo "{$type2} > {$value1}: " . ($value2 > $value1 ? 'true' : 'false') . "\n";
28+
echo "{$type2} >= {$value1}: " . ($value2 >= $value1 ? 'true' : 'false') . "\n";
29+
echo "{$type2} == {$value1}: " . ($value2 == $value1 ? 'true' : 'false') . "\n";
30+
echo "{$type2} <= {$value1}: " . ($value2 <= $value1 ? 'true' : 'false') . "\n";
31+
echo "{$type2} < {$value1}: " . ($value2 < $value1 ? 'true' : 'false') . "\n";
32+
33+
echo "\n";
34+
}
35+
?>
36+
--EXPECT--
37+
========== with null ==========
38+
100.0000 > null: true
39+
100.0000 >= null: true
40+
100.0000 == null: false
41+
100.0000 <= null: false
42+
100.0000 < null: false
43+
44+
inversion
45+
null > 100.0000: false
46+
null >= 100.0000: false
47+
null == 100.0000: false
48+
null <= 100.0000: true
49+
null < 100.0000: true
50+
51+
========== with string ==========
52+
100.0000 > string: false
53+
100.0000 >= string: false
54+
100.0000 == string: false
55+
100.0000 <= string: false
56+
100.0000 < string: false
57+
58+
inversion
59+
string > 100.0000: false
60+
string >= 100.0000: false
61+
string == 100.0000: false
62+
string <= 100.0000: false
63+
string < 100.0000: false
64+
65+
========== with object ==========
66+
100.0000 > object: false
67+
100.0000 >= object: false
68+
100.0000 == object: false
69+
100.0000 <= object: false
70+
100.0000 < object: false
71+
72+
inversion
73+
object > 100.0000: false
74+
object >= 100.0000: false
75+
object == 100.0000: false
76+
object <= 100.0000: false
77+
object < 100.0000: false
78+
79+
========== with array ==========
80+
100.0000 > array: false
81+
100.0000 >= array: false
82+
100.0000 == array: false
83+
100.0000 <= array: false
84+
100.0000 < array: false
85+
86+
inversion
87+
array > 100.0000: false
88+
array >= 100.0000: false
89+
array == 100.0000: false
90+
array <= 100.0000: false
91+
array < 100.0000: false
92+
93+
========== with resource ==========
94+
100.0000 > resource: false
95+
100.0000 >= resource: false
96+
100.0000 == resource: false
97+
100.0000 <= resource: false
98+
100.0000 < resource: false
99+
100+
inversion
101+
resource > 100.0000: false
102+
resource >= 100.0000: false
103+
resource == 100.0000: false
104+
resource <= 100.0000: false
105+
resource < 100.0000: false

0 commit comments

Comments
 (0)