From 2fe7719a44ed7a2b2bf47a9c8d8ce9d0f0f2aadb Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Nov 2024 21:57:20 +0900 Subject: [PATCH 1/2] Added early return case when result is 0 (#16697) fixes #16265 closes #16697 --- NEWS | 4 ++++ ext/bcmath/libbcmath/src/div.c | 5 +++++ ext/bcmath/tests/gh16265.phpt | 12 ++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 ext/bcmath/tests/gh16265.phpt diff --git a/NEWS b/NEWS index da14c247ee0ec..26bbf705270d1 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.4.0RC4 +- BcMath: + . Fixed bug GH-16265 (Added early return case when result is 0) + (Saki Takamachi). + - Core: . Fixed bug GH-16574 (Incorrect error "undefined method" messages). (nielsdos) diff --git a/ext/bcmath/libbcmath/src/div.c b/ext/bcmath/libbcmath/src/div.c index 35ca450ceb78c..a9c001afcc94b 100644 --- a/ext/bcmath/libbcmath/src/div.c +++ b/ext/bcmath/libbcmath/src/div.c @@ -444,6 +444,11 @@ bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale) /* Length of numerator data that can be read */ size_t numerator_readable_len = numeratorend - numeratorptr + 1; + if (divisor_len > numerator_readable_len + numerator_bottom_extension) { + *quot = bc_copy_num(BCG(_zero_)); + return true; + } + /* If divisor is 1 here, return the result of adjusting the decimal point position of numerator. */ if (divisor_len == 1 && *divisorptr == 1) { if (numerator_len == 0) { diff --git a/ext/bcmath/tests/gh16265.phpt b/ext/bcmath/tests/gh16265.phpt new file mode 100644 index 0000000000000..bc562d81df1ad --- /dev/null +++ b/ext/bcmath/tests/gh16265.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-16265 Segmentation fault (index oob) in ext/bcmath/libbcmath/src/convert.c:155 +--EXTENSIONS-- +bcmath +--INI-- +bcmath.scale=0 +--FILE-- + +--EXPECT-- +0.000000000 From fd1dff988e98f232fff3e964ef0abdd52b14f5ca Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Nov 2024 20:04:50 +0900 Subject: [PATCH 2/2] Fixed a bug where size_t underflows (#16696) fixes #16262 closes #16696 --- NEWS | 1 + ext/bcmath/libbcmath/src/div.c | 2 +- ext/bcmath/tests/gh16262.phpt | 158 +++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 ext/bcmath/tests/gh16262.phpt diff --git a/NEWS b/NEWS index 26bbf705270d1..17884e5774836 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PHP NEWS - BcMath: . Fixed bug GH-16265 (Added early return case when result is 0) (Saki Takamachi). + . Fixed bug GH-16262 (Fixed a bug where size_t underflows) (Saki Takamachi). - Core: . Fixed bug GH-16574 (Incorrect error "undefined method" messages). diff --git a/ext/bcmath/libbcmath/src/div.c b/ext/bcmath/libbcmath/src/div.c index a9c001afcc94b..9c8344fe771a8 100644 --- a/ext/bcmath/libbcmath/src/div.c +++ b/ext/bcmath/libbcmath/src/div.c @@ -434,7 +434,7 @@ bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale) numerator_bottom_extension -= scale_diff; } else { numerator_bottom_extension = 0; - numeratorend -= scale_diff - numerator_bottom_extension; + numeratorend -= scale_diff > numerator_top_extension ? scale_diff - numerator_top_extension : 0; } } else { numerator_bottom_extension += scale - numerator_scale; diff --git a/ext/bcmath/tests/gh16262.phpt b/ext/bcmath/tests/gh16262.phpt new file mode 100644 index 0000000000000..e932bae2301ab --- /dev/null +++ b/ext/bcmath/tests/gh16262.phpt @@ -0,0 +1,158 @@ +--TEST-- +GH-16262 Stack buffer overflow in ext/bcmath/libbcmath/src/div.c:459 +--EXTENSIONS-- +bcmath +--INI-- +bcmath.scale=0 +--FILE-- +div('1000', $scale), + ); + echo "1 / 2000:\n"; + var_dump( + bcdiv('1', '2000', $scale), + (new BcMath\Number('1'))->div('2000', $scale), + ); + echo "\n"; +} +?> +--EXPECT-- +========== scale: null ========== +1 / 1000: +string(1) "0" +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "0.001" + ["scale"]=> + int(3) +} +1 / 2000: +string(1) "0" +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "0.0005" + ["scale"]=> + int(4) +} + +========== scale: 0 ========== +1 / 1000: +string(1) "0" +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +1 / 2000: +string(1) "0" +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +========== scale: 1 ========== +1 / 1000: +string(3) "0.0" +object(BcMath\Number)#2 (2) { + ["value"]=> + string(3) "0.0" + ["scale"]=> + int(1) +} +1 / 2000: +string(3) "0.0" +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "0.0" + ["scale"]=> + int(1) +} + +========== scale: 2 ========== +1 / 1000: +string(4) "0.00" +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} +1 / 2000: +string(4) "0.00" +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +========== scale: 3 ========== +1 / 1000: +string(5) "0.001" +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "0.001" + ["scale"]=> + int(3) +} +1 / 2000: +string(5) "0.000" +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "0.000" + ["scale"]=> + int(3) +} + +========== scale: 4 ========== +1 / 1000: +string(6) "0.0010" +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "0.0010" + ["scale"]=> + int(4) +} +1 / 2000: +string(6) "0.0005" +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "0.0005" + ["scale"]=> + int(4) +} + +========== scale: 5 ========== +1 / 1000: +string(7) "0.00100" +object(BcMath\Number)#2 (2) { + ["value"]=> + string(7) "0.00100" + ["scale"]=> + int(5) +} +1 / 2000: +string(7) "0.00050" +object(BcMath\Number)#1 (2) { + ["value"]=> + string(7) "0.00050" + ["scale"]=> + int(5) +}