Commit 6030e5637f7 for php
commit 6030e5637f7d9b06234772ecf37bf5ba4b1024bf
Merge: 0826ebea2be 8184e9efec2
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Tue Sep 29 15:47:46 2026 -0400
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
ext/bcmath: Clear the sign of BcMath\Number results that truncate to zero
diff --cc NEWS
index 1320a09aa7e,a011c225aa6..40eaef9775a
--- a/NEWS
+++ b/NEWS
@@@ -1,12 -1,20 +1,16 @@@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-?? ??? ????, PHP 8.4.27
+?? ??? ????, PHP 8.5.12
+ - BCMath:
+ . Fixed BcMath\Number results that truncate to zero keeping a negative sign
+ and comparing less than zero. (Ilia Alshanetsky)
+
-- CLI
- . Fix GH-22567 (Windows ZTS CLI SAPI should refresh its TSRMLS cache during
- request activation). (matyhtf)
- . Fixed bug GH-23764 (Built-in server leaks a file descriptor on every HEAD
- request for a static file). (jakubskopal)
- . Fixed crash in the built-in server when a client is reset before being
- accepted. (David Carlier)
-
-- Core
+- Core:
+ . Fixed bug GH-23644 (Optimizer leaves a constant-vs-constant comparison
+ unfolded, crashing the VM in zval_undefined_cv). (ndossche)
+ . Fixed OSS-Fuzz 532353396 (assertion failure with static type). (Girgias)
+ . Fix GH-23662 (Avoid NAN warning in print_r()). (CodedByManish)
. Fix GH-21999: GC inconsistency with lazy object, var_dump(), and object
comparison. (Arnaud)
. Fixed OSS-Fuzz #536440507 (Immutable class incorrect assertion).
diff --cc ext/bcmath/libbcmath/src/div.c
index 24ec9a64d77,a45ffdb7757..56db164e444
--- a/ext/bcmath/libbcmath/src/div.c
+++ b/ext/bcmath/libbcmath/src/div.c
@@@ -349,63 -345,145 +349,71 @@@ bool bc_divide(bc_num numerator, bc_nu
/* If divisor is 1 / -1, the quotient's n_value is equal to numerator's n_value. */
if (_bc_do_compare(divisor, BCG(_one_), divisor->n_scale, false) == BCMATH_EQUAL) {
- size_t quot_scale = MIN(numerator->n_scale, scale);
- *quot = bc_new_num_nonzeroed(numerator->n_len, quot_scale);
- char *qptr = (*quot)->n_value;
- memcpy(qptr, numerator->n_value, numerator->n_len + quot_scale);
- _bc_rm_leading_zeros(*quot);
+ bc_divide_by_one(numerator, quot, quot_scale);
- (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
+ if (bc_is_zero(*quot)) {
+ (*quot)->n_sign = PLUS;
+ } else {
+ (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
+ }
return true;
}
- char *numeratorptr = numerator->n_value;
- char *numeratorend = numeratorptr + numerator->n_len + numerator->n_scale - 1;
- size_t numerator_len = numerator->n_len;
- size_t numerator_scale = numerator->n_scale;
-
- char *divisorptr = divisor->n_value;
- char *divisorend = divisorptr + divisor->n_len + divisor->n_scale - 1;
- size_t divisor_len = divisor->n_len;
- size_t divisor_scale = divisor->n_scale;
- size_t divisor_int_right_zeros = 0;
-
- /* remove divisor trailing zeros */
- while (*divisorend == 0 && divisor_scale > 0) {
- divisorend--;
- divisor_scale--;
- }
- while (*divisorend == 0) {
- divisorend--;
- divisor_int_right_zeros++;
- }
+ const char *numeratorptr = numerator->n_value;
+ size_t numerator_size = numerator->n_len + quot_scale + divisor->n_scale;
- if (*numeratorptr == 0 && numerator_len == 1) {
- numeratorptr++;
- numerator_len = 0;
- }
+ const char *divisorptr = divisor->n_value;
+ size_t divisor_size = divisor->n_len + divisor->n_scale;
- size_t numerator_top_extension = 0;
- size_t numerator_bottom_extension = 0;
- if (divisor_scale > 0) {
- /*
- * e.g. divisor_scale = 4
- * divisor = .0002, to be 2 or divisor = 200.001, to be 200001
- * numerator = .03, to be 300 or numerator = .000003, to be .03
- * numerator may become longer than the original data length due to the addition of
- * trailing zeros in the integer part.
- */
- numerator_len += divisor_scale;
- numerator_bottom_extension = numerator_scale < divisor_scale ? divisor_scale - numerator_scale : 0;
- numerator_scale = numerator_scale > divisor_scale ? numerator_scale - divisor_scale : 0;
- divisor_len += divisor_scale;
- divisor_scale = 0;
- } else if (divisor_int_right_zeros > 0) {
- /*
- * e.g. divisor_int_right_zeros = 4
- * divisor = 2000, to be 2
- * numerator = 30, to be .03 or numerator = 30000, to be 30
- * Also, numerator may become longer than the original data length due to the addition of
- * leading zeros in the fractional part.
- */
- numerator_top_extension = numerator_len < divisor_int_right_zeros ? divisor_int_right_zeros - numerator_len : 0;
- numerator_len = numerator_len > divisor_int_right_zeros ? numerator_len - divisor_int_right_zeros : 0;
- numerator_scale += divisor_int_right_zeros;
- divisor_len -= divisor_int_right_zeros;
- divisor_scale = 0;
- }
-
- /* remove numerator leading zeros */
- while (*numeratorptr == 0 && numerator_len > 0) {
+ /* check and remove numerator leading zeros */
+ size_t numerator_leading_zeros = 0;
+ while (*numeratorptr == 0) {
numeratorptr++;
- numerator_len--;
+ numerator_leading_zeros++;
+ if (numerator_leading_zeros == numerator_size) {
+ goto quot_zero;
+ }
}
- /* remove divisor leading zeros */
+ numerator_size -= numerator_leading_zeros;
+
+ /* check and remove divisor leading zeros */
while (*divisorptr == 0) {
divisorptr++;
- divisor_len--;
+ divisor_size--;
}
- /* Considering the scale specification, the quotient is always 0 if this condition is met */
- if (divisor_len > numerator_len + scale) {
- *quot = bc_copy_num(BCG(_zero_));
- return true;
+ if (divisor_size > numerator_size) {
+ goto quot_zero;
}
- /* Length of numerator data that can be read */
- size_t numerator_readable_len = numeratorend - numeratorptr + 1;
-
- /* set scale to numerator */
- if (numerator_scale > scale) {
- size_t scale_diff = numerator_scale - scale;
- if (numerator_bottom_extension > scale_diff) {
- numerator_bottom_extension -= scale_diff;
- } else {
- numerator_bottom_extension = 0;
- if (EXPECTED(numerator_readable_len > scale_diff)) {
- numerator_readable_len -= scale_diff;
- numeratorend -= scale_diff;
- } else {
- numerator_readable_len = 0;
- numeratorend = numeratorptr;
- }
+ /* check and remove divisor trailing zeros. The divisor is not 0, so leave only one digit */
+ size_t divisor_trailing_zeros = 0;
+ for (size_t i = divisor_size - 1; i > 0; i--) {
+ if (divisorptr[i] != 0) {
+ break;
}
- numerator_top_extension = MIN(numerator_top_extension, scale);
- } else {
- numerator_bottom_extension += scale - numerator_scale;
+ divisor_trailing_zeros++;
}
- numerator_scale = scale;
+ divisor_size -= divisor_trailing_zeros;
+ numerator_size -= divisor_trailing_zeros;
- if (divisor_len > numerator_readable_len + numerator_bottom_extension) {
- *quot = bc_copy_num(BCG(_zero_));
- return true;
+ size_t quot_size = numerator_size - divisor_size + 1; /* numerator_size >= divisor_size */
+ if (quot_size > quot_scale) {
+ *quot = bc_new_num_nonzeroed(quot_size - quot_scale, quot_scale);
+ } else {
+ *quot = bc_new_num_nonzeroed(1, quot_scale); /* 1 is for 0 */
}
- /* 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) {
- numerator_len = 1;
- numerator_top_extension++;
- }
- size_t quot_scale = numerator_scale > numerator_bottom_extension ? numerator_scale - numerator_bottom_extension : 0;
- numerator_bottom_extension = numerator_scale < numerator_bottom_extension ? numerator_bottom_extension - numerator_scale : 0;
+ /* Size that can be read from numeratorptr */
+ size_t numerator_readable_size = numerator->n_len + numerator->n_scale - numerator_leading_zeros;
- *quot = bc_new_num_nonzeroed(numerator_len, quot_scale);
- char *qptr = (*quot)->n_value;
- for (size_t i = 0; i < numerator_top_extension; i++) {
- *qptr++ = 0;
- }
- memcpy(qptr, numeratorptr, numerator_readable_len);
- qptr += numerator_readable_len;
- for (size_t i = 0; i < numerator_bottom_extension; i++) {
- *qptr++ = 0;
- }
+ /* If divisor is 1 here, return the result of adjusting the decimal point position of numerator. */
+ if (divisor_size == 1 && *divisorptr == 1) {
+ bc_divide_by_pow_10(numeratorptr, numerator_readable_size, quot, quot_size, quot_scale);
- (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
+ if (bc_is_zero(*quot)) {
+ (*quot)->n_sign = PLUS;
+ } else {
+ (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
+ }
return true;
}
diff --cc ext/bcmath/libbcmath/src/raise.c
index 959ba924e57,efb30f24ffc..ef39148327f
--- a/ext/bcmath/libbcmath/src/raise.c
+++ b/ext/bcmath/libbcmath/src/raise.c
@@@ -245,17 -92,22 +245,20 @@@ bc_raise_status bc_raise(bc_num base, l
/* Assign the value. */
if (is_neg) {
- if (bc_divide(BCG(_one_), temp, result, rscale) == false) {
- bc_free_num (&temp);
+ if (bc_divide(BCG(_one_), power, result, rscale) == false) {
bc_free_num (&power);
- return false;
+ return BC_RAISE_STATUS_DIVIDE_BY_ZERO;
}
- bc_free_num (&temp);
+ bc_free_num (&power);
} else {
bc_free_num (result);
- *result = temp;
+ *result = power;
(*result)->n_scale = MIN(scale, (*result)->n_scale);
+ if (bc_is_zero(*result)) {
+ (*result)->n_sign = PLUS;
+ }
}
- bc_free_num (&power);
- return true;
+ return BC_RAISE_STATUS_OK;
}
/* This is used internally by BCMath */