Skip to content

Commit 68247c0

Browse files
authored
Refactor BCMath bundledlib and extension (#10774)
* ext/bcmath: coding style: use indentation And add braces to block statements, as the current code was pretty much unreadable with how inconsistent it was. * ext/bcmath: Remove some useless header inclusions * ext/bcmath: Use standard C99 bool type instead of char * ext/bcmath: Include specific headers instead of config.h * Restructure definitions to reduce header inclusions * Use size_t as a more appropriate type * Remove unused variable full_scale * Refactor bc_raisemod() to get rid of Zend dependencies This separates the concerns of throwing exceptions back into the PHP_FUNCTION instead of being the responsibility of the library * Refactor bc_raise() to get rid of Zend dependencies This separates the concerns of throwing exceptions back into the PHP_FUNCTION instead of being the responsibility of the library * Refactor bc_divmod() and bc_modulo() to return bool Return false on division by 0 attempt instead of -1 and true on success instead of 0 * Refactor bc_divide() to return bool Return false on division by 0 attempt instead of -1 and true on success instead of 0
1 parent 0f20527 commit 68247c0

26 files changed

+1438
-1483
lines changed

ext/bcmath/bcmath.c

Lines changed: 68 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
ZEND_DECLARE_MODULE_GLOBALS(bcmath)
3333
static PHP_GINIT_FUNCTION(bcmath);
3434
static PHP_GSHUTDOWN_FUNCTION(bcmath);
35+
static PHP_MINIT_FUNCTION(bcmath);
36+
static PHP_MSHUTDOWN_FUNCTION(bcmath);
37+
static PHP_MINFO_FUNCTION(bcmath);
3538

3639
zend_module_entry bcmath_module_entry = {
3740
STANDARD_MODULE_HEADER,
@@ -341,15 +344,13 @@ PHP_FUNCTION(bcdiv)
341344
goto cleanup;
342345
}
343346

344-
switch (bc_divide(first, second, &result, scale)) {
345-
case 0: /* OK */
346-
RETVAL_STR(bc_num2str_ex(result, scale));
347-
break;
348-
case -1: /* division by zero */
349-
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
350-
break;
347+
if (!bc_divide(first, second, &result, scale)) {
348+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
349+
goto cleanup;
351350
}
352351

352+
RETVAL_STR(bc_num2str_ex(result, scale));
353+
353354
cleanup: {
354355
bc_free_num(&first);
355356
bc_free_num(&second);
@@ -397,15 +398,13 @@ PHP_FUNCTION(bcmod)
397398
goto cleanup;
398399
}
399400

400-
switch (bc_modulo(first, second, &result, scale)) {
401-
case 0:
402-
RETVAL_STR(bc_num2str_ex(result, scale));
403-
break;
404-
case -1:
405-
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
406-
break;
401+
if (!bc_modulo(first, second, &result, scale)) {
402+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
403+
goto cleanup;
407404
}
408405

406+
RETVAL_STR(bc_num2str_ex(result, scale));
407+
409408
cleanup: {
410409
bc_free_num(&first);
411410
bc_free_num(&second);
@@ -417,16 +416,16 @@ PHP_FUNCTION(bcmod)
417416
/* {{{ Returns the value of an arbitrary precision number raised to the power of another reduced by a modulus */
418417
PHP_FUNCTION(bcpowmod)
419418
{
420-
zend_string *left, *right, *modulus;
419+
zend_string *base_str, *exponent_str, *modulus_str;
421420
zend_long scale_param;
422421
bool scale_param_is_null = 1;
423-
bc_num first, second, mod, result;
422+
bc_num bc_base, bc_expo, bc_modulus, result;
424423
int scale = BCG(bc_precision);
425424

426425
ZEND_PARSE_PARAMETERS_START(3, 4)
427-
Z_PARAM_STR(left)
428-
Z_PARAM_STR(right)
429-
Z_PARAM_STR(modulus)
426+
Z_PARAM_STR(base_str)
427+
Z_PARAM_STR(exponent_str)
428+
Z_PARAM_STR(modulus_str)
430429
Z_PARAM_OPTIONAL
431430
Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
432431
ZEND_PARSE_PARAMETERS_END();
@@ -440,34 +439,53 @@ PHP_FUNCTION(bcpowmod)
440439
scale = (int) scale_param;
441440
}
442441

443-
bc_init_num(&first);
444-
bc_init_num(&second);
445-
bc_init_num(&mod);
442+
bc_init_num(&bc_base);
443+
bc_init_num(&bc_expo);
444+
bc_init_num(&bc_modulus);
446445
bc_init_num(&result);
447446

448-
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
447+
if (php_str2num(&bc_base, ZSTR_VAL(base_str)) == FAILURE) {
449448
zend_argument_value_error(1, "is not well-formed");
450449
goto cleanup;
451450
}
452451

453-
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
452+
if (php_str2num(&bc_expo, ZSTR_VAL(exponent_str)) == FAILURE) {
454453
zend_argument_value_error(2, "is not well-formed");
455454
goto cleanup;
456455
}
457456

458-
if (php_str2num(&mod, ZSTR_VAL(modulus)) == FAILURE) {
457+
if (php_str2num(&bc_modulus, ZSTR_VAL(modulus_str)) == FAILURE) {
459458
zend_argument_value_error(3, "is not well-formed");
460459
goto cleanup;
461460
}
462461

463-
if (bc_raisemod(first, second, mod, &result, scale) == SUCCESS) {
464-
RETVAL_STR(bc_num2str_ex(result, scale));
462+
raise_mod_status status = bc_raisemod(bc_base, bc_expo, bc_modulus, &result, scale);
463+
switch (status) {
464+
case BASE_HAS_FRACTIONAL:
465+
zend_argument_value_error(1, "cannot have a fractional part");
466+
goto cleanup;
467+
case EXPO_HAS_FRACTIONAL:
468+
zend_argument_value_error(2, "cannot have a fractional part");
469+
goto cleanup;
470+
case EXPO_IS_NEGATIVE:
471+
zend_argument_value_error(2, "must be greater than or equal to 0");
472+
goto cleanup;
473+
case MOD_HAS_FRACTIONAL:
474+
zend_argument_value_error(3, "cannot have a fractional part");
475+
goto cleanup;
476+
case MOD_IS_ZERO:
477+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
478+
goto cleanup;
479+
case OK:
480+
RETVAL_STR(bc_num2str_ex(result, scale));
481+
break;
482+
EMPTY_SWITCH_DEFAULT_CASE();
465483
}
466484

467485
cleanup: {
468-
bc_free_num(&first);
469-
bc_free_num(&second);
470-
bc_free_num(&mod);
486+
bc_free_num(&bc_base);
487+
bc_free_num(&bc_expo);
488+
bc_free_num(&bc_modulus);
471489
bc_free_num(&result);
472490
};
473491
}
@@ -476,15 +494,15 @@ PHP_FUNCTION(bcpowmod)
476494
/* {{{ Returns the value of an arbitrary precision number raised to the power of another */
477495
PHP_FUNCTION(bcpow)
478496
{
479-
zend_string *left, *right;
497+
zend_string *base_str, *exponent_str;
480498
zend_long scale_param;
481499
bool scale_param_is_null = 1;
482-
bc_num first, second, result;
500+
bc_num first, bc_exponent, result;
483501
int scale = BCG(bc_precision);
484502

485503
ZEND_PARSE_PARAMETERS_START(2, 3)
486-
Z_PARAM_STR(left)
487-
Z_PARAM_STR(right)
504+
Z_PARAM_STR(base_str)
505+
Z_PARAM_STR(exponent_str)
488506
Z_PARAM_OPTIONAL
489507
Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
490508
ZEND_PARSE_PARAMETERS_END();
@@ -499,26 +517,37 @@ PHP_FUNCTION(bcpow)
499517
}
500518

501519
bc_init_num(&first);
502-
bc_init_num(&second);
520+
bc_init_num(&bc_exponent);
503521
bc_init_num(&result);
504522

505-
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
523+
if (php_str2num(&first, ZSTR_VAL(base_str)) == FAILURE) {
506524
zend_argument_value_error(1, "is not well-formed");
507525
goto cleanup;
508526
}
509527

510-
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
528+
if (php_str2num(&bc_exponent, ZSTR_VAL(exponent_str)) == FAILURE) {
511529
zend_argument_value_error(2, "is not well-formed");
512530
goto cleanup;
513531
}
514532

515-
bc_raise (first, second, &result, scale);
533+
/* Check the exponent for scale digits and convert to a long. */
534+
if (bc_exponent->n_scale != 0) {
535+
zend_argument_value_error(2, "cannot have a fractional part");
536+
goto cleanup;
537+
}
538+
long exponent = bc_num2long(bc_exponent);
539+
if (exponent == 0 && (bc_exponent->n_len > 1 || bc_exponent->n_value[0] != 0)) {
540+
zend_argument_value_error(2, "is too large");
541+
goto cleanup;
542+
}
543+
544+
bc_raise(first, exponent, &result, scale);
516545

517546
RETVAL_STR(bc_num2str_ex(result, scale));
518547

519548
cleanup: {
520549
bc_free_num(&first);
521-
bc_free_num(&second);
550+
bc_free_num(&bc_exponent);
522551
bc_free_num(&result);
523552
};
524553
}

ext/bcmath/libbcmath/src/add.c

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,55 +29,49 @@
2929
3030
*************************************************************************/
3131

32-
#include <config.h>
33-
#include <stdio.h>
34-
#include <stdlib.h>
35-
#include <ctype.h>
36-
#include <stdarg.h>
3732
#include "bcmath.h"
3833
#include "private.h"
34+
#include <stddef.h>
35+
#include <string.h>
3936

4037

4138
/* Here is the full add routine that takes care of negative numbers.
4239
N1 is added to N2 and the result placed into RESULT. SCALE_MIN
4340
is the minimum scale for the result. */
4441

45-
void bc_add (bc_num n1, bc_num n2, bc_num *result, int scale_min)
42+
void bc_add (bc_num n1, bc_num n2, bc_num *result, size_t scale_min)
4643
{
47-
bc_num sum = NULL;
48-
int cmp_res;
49-
int res_scale;
44+
bc_num sum = NULL;
45+
int cmp_res;
46+
size_t res_scale;
5047

51-
if (n1->n_sign == n2->n_sign)
52-
{
53-
sum = _bc_do_add (n1, n2, scale_min);
54-
sum->n_sign = n1->n_sign;
55-
}
56-
else
57-
{
58-
/* subtraction must be done. */
59-
cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */
60-
switch (cmp_res)
61-
{
62-
case -1:
63-
/* n1 is less than n2, subtract n1 from n2. */
64-
sum = _bc_do_sub (n2, n1, scale_min);
65-
sum->n_sign = n2->n_sign;
66-
break;
67-
case 0:
68-
/* They are equal! return zero with the correct scale! */
69-
res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
70-
sum = bc_new_num (1, res_scale);
71-
memset (sum->n_value, 0, res_scale+1);
72-
break;
73-
case 1:
74-
/* n2 is less than n1, subtract n2 from n1. */
75-
sum = _bc_do_sub (n1, n2, scale_min);
76-
sum->n_sign = n1->n_sign;
48+
if (n1->n_sign == n2->n_sign) {
49+
sum = _bc_do_add (n1, n2, scale_min);
50+
sum->n_sign = n1->n_sign;
51+
} else {
52+
/* subtraction must be done. */
53+
/* Compare magnitudes. */
54+
cmp_res = _bc_do_compare(n1, n2, false, false);
55+
switch (cmp_res) {
56+
case -1:
57+
/* n1 is less than n2, subtract n1 from n2. */
58+
sum = _bc_do_sub (n2, n1, scale_min);
59+
sum->n_sign = n2->n_sign;
60+
break;
61+
case 0:
62+
/* They are equal! return zero with the correct scale! */
63+
res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
64+
sum = bc_new_num (1, res_scale);
65+
memset (sum->n_value, 0, res_scale+1);
66+
break;
67+
case 1:
68+
/* n2 is less than n1, subtract n2 from n1. */
69+
sum = _bc_do_sub (n1, n2, scale_min);
70+
sum->n_sign = n1->n_sign;
71+
}
7772
}
78-
}
7973

80-
/* Clean up and return. */
81-
bc_free_num (result);
82-
*result = sum;
74+
/* Clean up and return. */
75+
bc_free_num (result);
76+
*result = sum;
8377
}

0 commit comments

Comments
 (0)