Skip to content

Commit 9caa0a7

Browse files
jorgsowailuuu1994
authored andcommitted
Fix bc_str2num accepting strings with embedded null bytes
Closes GH-21492
1 parent 00c4295 commit 9caa0a7

3 files changed

Lines changed: 65 additions & 3 deletions

File tree

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ PHP NEWS
1717
ReflectionProperty::skipLazyInitialization after failed LazyProxy
1818
initialization). (Arnaud)
1919

20+
- BCMath:
21+
. Added NUL-byte validation to BCMath functions. (jorgsowa)
22+
2023
- Date:
2124
. Update timelib to 2022.16. (Derick)
2225

ext/bcmath/libbcmath/src/str2num.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, siz
131131
const char *decimal_point = (*ptr == '.') ? ptr : NULL;
132132

133133
/* If a non-digit and non-decimal-point indicator is in the string, i.e. an invalid character */
134-
if (UNEXPECTED(!decimal_point && *ptr != '\0')) {
134+
if (UNEXPECTED(!decimal_point && ptr != end)) {
135135
goto fail;
136136
}
137137

@@ -140,7 +140,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, siz
140140
/* search */
141141
fractional_ptr = fractional_end = decimal_point + 1;
142142
/* For strings that end with a decimal point, such as "012." */
143-
if (UNEXPECTED(*fractional_ptr == '\0')) {
143+
if (UNEXPECTED(fractional_ptr == end)) {
144144
if (full_scale) {
145145
*full_scale = 0;
146146
}
@@ -149,7 +149,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, siz
149149

150150
/* validate */
151151
fractional_end = bc_count_digits(fractional_ptr, end);
152-
if (UNEXPECTED(*fractional_end != '\0')) {
152+
if (UNEXPECTED(fractional_end != end)) {
153153
/* invalid num */
154154
goto fail;
155155
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
bcmath strings with embedded null bytes must be rejected as not well-formed
3+
--EXTENSIONS--
4+
bcmath
5+
--FILE--
6+
<?php
7+
$cases = [
8+
"100\x005",
9+
"1.2\x003",
10+
"\x00123",
11+
];
12+
13+
$calls = [
14+
fn($s) => bcadd($s, "0"),
15+
fn($s) => bcsub($s, "0"),
16+
fn($s) => bcmul($s, "1"),
17+
fn($s) => bcdiv($s, "1"),
18+
fn($s) => bcmod($s, "7"),
19+
fn($s) => bcpow($s, "1"),
20+
fn($s) => bccomp($s, "0"),
21+
fn($s) => bcsqrt($s),
22+
];
23+
24+
foreach ($cases as $s) {
25+
foreach ($calls as $fn) {
26+
try {
27+
$fn($s);
28+
echo "FAIL: accepted\n";
29+
} catch (\ValueError $e) {
30+
echo $e->getMessage() . "\n";
31+
}
32+
}
33+
}
34+
?>
35+
--EXPECT--
36+
bcadd(): Argument #1 ($num1) is not well-formed
37+
bcsub(): Argument #1 ($num1) is not well-formed
38+
bcmul(): Argument #1 ($num1) is not well-formed
39+
bcdiv(): Argument #1 ($num1) is not well-formed
40+
bcmod(): Argument #1 ($num1) is not well-formed
41+
bcpow(): Argument #1 ($num) is not well-formed
42+
bccomp(): Argument #1 ($num1) is not well-formed
43+
bcsqrt(): Argument #1 ($num) is not well-formed
44+
bcadd(): Argument #1 ($num1) is not well-formed
45+
bcsub(): Argument #1 ($num1) is not well-formed
46+
bcmul(): Argument #1 ($num1) is not well-formed
47+
bcdiv(): Argument #1 ($num1) is not well-formed
48+
bcmod(): Argument #1 ($num1) is not well-formed
49+
bcpow(): Argument #1 ($num) is not well-formed
50+
bccomp(): Argument #1 ($num1) is not well-formed
51+
bcsqrt(): Argument #1 ($num) is not well-formed
52+
bcadd(): Argument #1 ($num1) is not well-formed
53+
bcsub(): Argument #1 ($num1) is not well-formed
54+
bcmul(): Argument #1 ($num1) is not well-formed
55+
bcdiv(): Argument #1 ($num1) is not well-formed
56+
bcmod(): Argument #1 ($num1) is not well-formed
57+
bcpow(): Argument #1 ($num) is not well-formed
58+
bccomp(): Argument #1 ($num1) is not well-formed
59+
bcsqrt(): Argument #1 ($num) is not well-formed

0 commit comments

Comments
 (0)