Skip to content

Commit b575d03

Browse files
committed
Division/Modulo by 0 error in GMP extension
1 parent 3a56291 commit b575d03

12 files changed

+218
-171
lines changed

ext/gmp/gmp.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,14 @@ static int gmp_do_operation_ex(zend_uchar opcode, zval *result, zval *op1, zval
380380
case ZEND_DIV:
381381
DO_BINARY_UI_OP_EX(mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1);
382382
case ZEND_MOD:
383-
DO_BINARY_UI_OP_EX(mpz_mod, gmp_mpz_mod_ui, 1);
383+
gmp_zval_binary_ui_op(result, op1, op2, mpz_mod, gmp_mpz_mod_ui, 1);
384+
/* Free Division by zero error and rethrow a new modulo by zero one */
385+
if (UNEXPECTED(EG(exception) && EG(exception)->ce == zend_ce_division_by_zero_error)) {
386+
zend_clear_exception();
387+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
388+
return FAILURE;
389+
}
390+
return SUCCESS;
384391
case ZEND_SL:
385392
shift_operator_helper(mpz_mul_2exp, result, op1, op2, opcode);
386393
return SUCCESS;
@@ -728,10 +735,10 @@ static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *
728735
}
729736

730737
if (b_is_zero) {
731-
php_error_docref(NULL, E_WARNING, "Zero operand not allowed");
738+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
732739
FREE_GMP_TEMP(temp_a);
733740
FREE_GMP_TEMP(temp_b);
734-
RETURN_FALSE;
741+
RETURN_THROWS();
735742
}
736743
}
737744

@@ -775,10 +782,10 @@ static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval
775782
}
776783

777784
if (b_is_zero) {
778-
php_error_docref(NULL, E_WARNING, "Zero operand not allowed");
785+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
779786
FREE_GMP_TEMP(temp_a);
780787
FREE_GMP_TEMP(temp_b);
781-
RETURN_FALSE;
788+
RETURN_THROWS();
782789
}
783790
}
784791

@@ -1152,6 +1159,12 @@ ZEND_FUNCTION(gmp_div_q)
11521159
ZEND_FUNCTION(gmp_mod)
11531160
{
11541161
gmp_binary_ui_op_no_zero(mpz_mod, gmp_mpz_mod_ui);
1162+
/* Clear division by zero and rethrow a modulo by zero exception */
1163+
if (UNEXPECTED(EG(exception) && EG(exception)->ce == zend_ce_division_by_zero_error)) {
1164+
zend_clear_exception();
1165+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
1166+
RETURN_THROWS();
1167+
}
11551168
}
11561169
/* }}} */
11571170

@@ -1300,7 +1313,7 @@ ZEND_FUNCTION(gmp_powm)
13001313
FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base, 3);
13011314

13021315
if (!mpz_cmp_ui(gmpnum_mod, 0)) {
1303-
zend_argument_value_error(3, "must not be 0");
1316+
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
13041317
FREE_GMP_TEMP(temp_base);
13051318
FREE_GMP_TEMP(temp_exp);
13061319
FREE_GMP_TEMP(temp_mod);
@@ -1777,8 +1790,8 @@ ZEND_FUNCTION(gmp_random_range)
17771790
if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
17781791
if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
17791792
FREE_GMP_TEMP(temp_a);
1780-
php_error_docref(NULL, E_WARNING, "The minimum value must be less than the maximum value");
1781-
RETURN_FALSE;
1793+
zend_argument_value_error(1, "must be less than argument#2 ($maximum)");
1794+
RETURN_THROWS();
17821795
}
17831796

17841797
INIT_GMP_RETVAL(gmpnum_result);
@@ -1806,8 +1819,8 @@ ZEND_FUNCTION(gmp_random_range)
18061819
if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
18071820
FREE_GMP_TEMP(temp_b);
18081821
FREE_GMP_TEMP(temp_a);
1809-
php_error_docref(NULL, E_WARNING, "The minimum value must be less than the maximum value");
1810-
RETURN_FALSE;
1822+
zend_argument_value_error(1, "must be less than argument#2 ($maximum)");
1823+
RETURN_THROWS();
18111824
}
18121825

18131826
INIT_GMP_RETVAL(gmpnum_result);

ext/gmp/gmp.stub.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,38 +42,38 @@ function gmp_mul($a, $b): GMP {}
4242
* @param GMP|int|bool|string $a
4343
* @param GMP|int|bool|string $b
4444
*/
45-
function gmp_div_qr($a, $b, int $round = GMP_ROUND_ZERO): array|false {}
45+
function gmp_div_qr($a, $b, int $round = GMP_ROUND_ZERO): array {}
4646

4747
/**
4848
* @param GMP|int|bool|string $a
4949
* @param GMP|int|bool|string $b
5050
*/
51-
function gmp_div_q($a, $b, int $round = GMP_ROUND_ZERO): GMP|false {}
51+
function gmp_div_q($a, $b, int $round = GMP_ROUND_ZERO): GMP {}
5252

5353
/**
5454
* @param GMP|int|bool|string $a
5555
* @param GMP|int|bool|string $b
5656
*/
57-
function gmp_div_r($a, $b, int $round = GMP_ROUND_ZERO): GMP|false {}
57+
function gmp_div_r($a, $b, int $round = GMP_ROUND_ZERO): GMP {}
5858

5959
/**
6060
* @param GMP|int|bool|string $a
6161
* @param GMP|int|bool|string $b
6262
* @alias gmp_div_q
6363
*/
64-
function gmp_div($a, $b, int $round = GMP_ROUND_ZERO): GMP|false {}
64+
function gmp_div($a, $b, int $round = GMP_ROUND_ZERO): GMP {}
6565

6666
/**
6767
* @param GMP|int|bool|string $a
6868
* @param GMP|int|bool|string $b
6969
*/
70-
function gmp_mod($a, $b): GMP|false {}
70+
function gmp_mod($a, $b): GMP {}
7171

7272
/**
7373
* @param GMP|int|bool|string $a
7474
* @param GMP|int|bool|string $b
7575
*/
76-
function gmp_divexact($a, $b): GMP|false {}
76+
function gmp_divexact($a, $b): GMP {}
7777

7878
/** @param GMP|int|bool|string $a */
7979
function gmp_neg($a): GMP {}
@@ -175,7 +175,7 @@ function gmp_random_bits(int $bits): GMP {}
175175
* @param GMP|int|bool|string $min
176176
* @param GMP|int|bool|string $max
177177
**/
178-
function gmp_random_range($min, $max): GMP|false {}
178+
function gmp_random_range($min, $max): GMP {}
179179

180180
/**
181181
* @param GMP|int|bool|string $a

ext/gmp/gmp_arginfo.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: d261dbf5bb9bad76c8a5c3936ea75a7b6f6a4500 */
2+
* Stub hash: 85d3acaa684604b73f1fbbace19b397e9364acc1 */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_init, 0, 1, GMP, 0)
55
ZEND_ARG_INFO(0, number)
@@ -36,13 +36,13 @@ ZEND_END_ARG_INFO()
3636

3737
#define arginfo_gmp_mul arginfo_gmp_add
3838

39-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_gmp_div_qr, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE)
39+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gmp_div_qr, 0, 2, IS_ARRAY, 0)
4040
ZEND_ARG_INFO(0, a)
4141
ZEND_ARG_INFO(0, b)
4242
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, round, IS_LONG, 0, "GMP_ROUND_ZERO")
4343
ZEND_END_ARG_INFO()
4444

45-
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_gmp_div_q, 0, 2, GMP, MAY_BE_FALSE)
45+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_div_q, 0, 2, GMP, 0)
4646
ZEND_ARG_INFO(0, a)
4747
ZEND_ARG_INFO(0, b)
4848
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, round, IS_LONG, 0, "GMP_ROUND_ZERO")
@@ -52,12 +52,9 @@ ZEND_END_ARG_INFO()
5252

5353
#define arginfo_gmp_div arginfo_gmp_div_q
5454

55-
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_gmp_mod, 0, 2, GMP, MAY_BE_FALSE)
56-
ZEND_ARG_INFO(0, a)
57-
ZEND_ARG_INFO(0, b)
58-
ZEND_END_ARG_INFO()
55+
#define arginfo_gmp_mod arginfo_gmp_add
5956

60-
#define arginfo_gmp_divexact arginfo_gmp_mod
57+
#define arginfo_gmp_divexact arginfo_gmp_add
6158

6259
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_neg, 0, 1, GMP, 0)
6360
ZEND_ARG_INFO(0, a)
@@ -114,7 +111,10 @@ ZEND_END_ARG_INFO()
114111

115112
#define arginfo_gmp_lcm arginfo_gmp_add
116113

117-
#define arginfo_gmp_invert arginfo_gmp_mod
114+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_gmp_invert, 0, 2, GMP, MAY_BE_FALSE)
115+
ZEND_ARG_INFO(0, a)
116+
ZEND_ARG_INFO(0, b)
117+
ZEND_END_ARG_INFO()
118118

119119
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gmp_jacobi, 0, 2, IS_LONG, 0)
120120
ZEND_ARG_INFO(0, a)
@@ -139,7 +139,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_random_bits, 0, 1, GMP, 0)
139139
ZEND_ARG_TYPE_INFO(0, bits, IS_LONG, 0)
140140
ZEND_END_ARG_INFO()
141141

142-
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_gmp_random_range, 0, 2, GMP, MAY_BE_FALSE)
142+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_random_range, 0, 2, GMP, 0)
143143
ZEND_ARG_INFO(0, min)
144144
ZEND_ARG_INFO(0, max)
145145
ZEND_END_ARG_INFO()

ext/gmp/tests/bug32773.phpt

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ Bug #32773 (binary GMP functions returns unexpected value, when second parameter
77
echo '10 + 0 = ', gmp_strval(gmp_add(10, 0)), "\n";
88
echo '10 + "0" = ', gmp_strval(gmp_add(10, '0')), "\n";
99

10-
echo gmp_strval(gmp_div(10, 0))."\n";
11-
echo gmp_strval(gmp_div_qr(10, 0))."\n";
10+
try {
11+
var_dump(gmp_div(10, 0));
12+
} catch (\DivisionByZeroError $e) {
13+
echo $e->getMessage() . \PHP_EOL;
14+
}
15+
try {
16+
var_dump(gmp_div_qr(10, 0));
17+
} catch (\DivisionByZeroError $e) {
18+
echo $e->getMessage() . \PHP_EOL;
19+
}
1220

1321
?>
14-
--EXPECTF--
22+
--EXPECT--
1523
10 + 0 = 10
1624
10 + "0" = 10
17-
18-
Warning: gmp_div(): Zero operand not allowed in %s on line %d
19-
0
20-
21-
Warning: gmp_div_qr(): Zero operand not allowed in %s on line %d
22-
0
25+
Division by zero
26+
Division by zero

ext/gmp/tests/gmp_div_q.phpt

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ gmp_div_q() tests
66
<?php
77

88
var_dump(gmp_div_q(0,1));
9-
var_dump(gmp_div_q(1,0));
9+
10+
try {
11+
var_dump(gmp_div_q(1, 0));
12+
} catch (\DivisionByZeroError $e) {
13+
echo $e->getMessage() . \PHP_EOL;
14+
}
15+
1016
var_dump(gmp_div_q(12653,23482734));
1117
try {
1218
var_dump(gmp_div_q(12653,23482734, 10));
@@ -35,40 +41,38 @@ try {
3541

3642
echo "Done\n";
3743
?>
38-
--EXPECTF--
39-
object(GMP)#%d (1) {
44+
--EXPECT--
45+
object(GMP)#1 (1) {
4046
["num"]=>
4147
string(1) "0"
4248
}
43-
44-
Warning: gmp_div_q(): Zero operand not allowed in %s on line %d
45-
bool(false)
46-
object(GMP)#%d (1) {
49+
Division by zero
50+
object(GMP)#2 (1) {
4751
["num"]=>
4852
string(1) "0"
4953
}
5054
gmp_div_q(): Argument #3 ($round) must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF
51-
object(GMP)#%d (1) {
55+
object(GMP)#1 (1) {
5256
["num"]=>
5357
string(4) "9131"
5458
}
55-
object(GMP)#%d (1) {
59+
object(GMP)#1 (1) {
5660
["num"]=>
5761
string(4) "9132"
5862
}
59-
object(GMP)#%d (1) {
63+
object(GMP)#1 (1) {
6064
["num"]=>
6165
string(4) "9131"
6266
}
63-
object(GMP)#%d (1) {
67+
object(GMP)#1 (1) {
6468
["num"]=>
6569
string(4) "9131"
6670
}
67-
object(GMP)#%d (1) {
71+
object(GMP)#1 (1) {
6872
["num"]=>
6973
string(4) "9132"
7074
}
71-
object(GMP)#%d (1) {
75+
object(GMP)#1 (1) {
7276
["num"]=>
7377
string(4) "9131"
7478
}

0 commit comments

Comments
 (0)