Skip to content

Commit 0877738

Browse files
committed
Fix bug #81119
The implementation for functions and operators is shared. However, we should not be generating argument errors for operators.
1 parent 67cf04f commit 0877738

File tree

5 files changed

+69
-31
lines changed

5 files changed

+69
-31
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ PHP NEWS
1616
. Fixed bug #81092 (fflush before stream_filter_remove corrupts stream).
1717
(cmb)
1818

19+
- GMP:
20+
. Fixed bug #81119 (GMP operators throw errors with wrong parameter names).
21+
(Nikita)
22+
1923
- OCI8:
2024
. Fixed bug #81088 (error in regression test for oci_fetch_object() and
2125
oci_fetch_array()). (Máté)

ext/gmp/gmp.c

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ if (IS_GMP(zval)) { \
175175

176176
static void gmp_strval(zval *result, mpz_t gmpnum, int base);
177177
static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
178-
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg);
178+
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator);
179179

180180
/*
181181
* The gmp_*_op functions provide an implementation for several common types
@@ -194,7 +194,7 @@ typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong);
194194
typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
195195
typedef gmp_ulong (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong);
196196

197-
static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero);
197+
static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator);
198198
static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero);
199199
static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op);
200200

@@ -350,11 +350,10 @@ static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zva
350350
}
351351
}
352352

353-
#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
354-
gmp_zval_binary_ui_op( \
355-
result, op1, op2, op, uop, check_b_zero \
356-
); \
357-
if (UNEXPECTED(EG(exception))) { return FAILURE; } \
353+
#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
354+
gmp_zval_binary_ui_op( \
355+
result, op1, op2, op, uop, check_b_zero, /* is_operator */ true); \
356+
if (UNEXPECTED(EG(exception))) { return FAILURE; } \
358357
return SUCCESS;
359358

360359
#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0)
@@ -428,7 +427,7 @@ static int gmp_compare(zval *op1, zval *op2) /* {{{ */
428427
{
429428
zval result;
430429

431-
gmp_cmp(&result, op1, op2);
430+
gmp_cmp(&result, op1, op2, /* is_operator */ true);
432431

433432
/* An error/exception occurs if one of the operands is not a numeric string
434433
* or an object which is different from GMP */
@@ -613,13 +612,11 @@ static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, ui
613612

614613
ret = mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), (int) base);
615614
if (-1 == ret) {
616-
/* if unserializing */
617615
if (arg_pos == 0) {
618-
php_error_docref(NULL, E_WARNING,
619-
"Cannot convert variable to GMP, it is not an integer string");
620-
return FAILURE;
616+
zend_value_error("Number is not an integer string");
617+
} else {
618+
zend_argument_value_error(arg_pos, "is not an integer string");
621619
}
622-
zend_argument_value_error(arg_pos, "is not an integer string");
623620
return FAILURE;
624621
}
625622

@@ -628,7 +625,13 @@ static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, ui
628625
default: {
629626
zend_long lval;
630627
if (!zend_parse_arg_long_slow(val, &lval)) {
631-
zend_argument_type_error(arg_pos, "must be of type GMP|string|int, %s given", zend_zval_type_name(val));
628+
if (arg_pos == 0) {
629+
zend_type_error(
630+
"Number must be of type GMP|string|int, %s given", zend_zval_type_name(val));
631+
} else {
632+
zend_argument_type_error(arg_pos,
633+
"must be of type GMP|string|int, %s given", zend_zval_type_name(val));
634+
}
632635
return FAILURE;
633636
}
634637

@@ -670,20 +673,20 @@ static void gmp_strval(zval *result, mpz_t gmpnum, int base) /* {{{ */
670673
}
671674
/* }}} */
672675

673-
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg) /* {{{ */
676+
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator) /* {{{ */
674677
{
675678
mpz_ptr gmpnum_a, gmpnum_b;
676679
gmp_temp_t temp_a, temp_b;
677680
zend_bool use_si = 0;
678681
zend_long res;
679682

680-
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
683+
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1);
681684

682685
if (Z_TYPE_P(b_arg) == IS_LONG) {
683686
use_si = 1;
684687
temp_b.is_used = 0;
685688
} else {
686-
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
689+
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2);
687690
}
688691

689692
if (use_si) {
@@ -702,18 +705,18 @@ static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg) /* {{{ */
702705
/* {{{ gmp_zval_binary_ui_op
703706
Execute GMP binary operation.
704707
*/
705-
static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero)
708+
static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator)
706709
{
707710
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
708711
gmp_temp_t temp_a, temp_b;
709712

710-
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
713+
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1);
711714

712715
if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
713716
gmpnum_b = NULL;
714717
temp_b.is_used = 0;
715718
} else {
716-
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
719+
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2);
717720
}
718721

719722
if (check_b_zero) {
@@ -810,7 +813,8 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op
810813
RETURN_THROWS();
811814
}
812815

813-
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero);
816+
gmp_zval_binary_ui_op(
817+
return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero, /* is_operator */ false);
814818
}
815819
/* }}} */
816820

@@ -1096,13 +1100,16 @@ ZEND_FUNCTION(gmp_div_r)
10961100

10971101
switch (round) {
10981102
case GMP_ROUND_ZERO:
1099-
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, gmp_mpz_tdiv_r_ui, 1);
1103+
gmp_zval_binary_ui_op(
1104+
return_value, a_arg, b_arg, mpz_tdiv_r, gmp_mpz_tdiv_r_ui, 1, /* is_operator */ false);
11001105
break;
11011106
case GMP_ROUND_PLUSINF:
1102-
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, gmp_mpz_cdiv_r_ui, 1);
1107+
gmp_zval_binary_ui_op(
1108+
return_value, a_arg, b_arg, mpz_cdiv_r, gmp_mpz_cdiv_r_ui, 1, /* is_operator */ false);
11031109
break;
11041110
case GMP_ROUND_MINUSINF:
1105-
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, gmp_mpz_fdiv_r_ui, 1);
1111+
gmp_zval_binary_ui_op(
1112+
return_value, a_arg, b_arg, mpz_fdiv_r, gmp_mpz_fdiv_r_ui, 1, /* is_operator */ false);
11061113
break;
11071114
default:
11081115
zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
@@ -1123,13 +1130,16 @@ ZEND_FUNCTION(gmp_div_q)
11231130

11241131
switch (round) {
11251132
case GMP_ROUND_ZERO:
1126-
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1);
1133+
gmp_zval_binary_ui_op(
1134+
return_value, a_arg, b_arg, mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1, /* is_operator */ false);
11271135
break;
11281136
case GMP_ROUND_PLUSINF:
1129-
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, gmp_mpz_cdiv_q_ui, 1);
1137+
gmp_zval_binary_ui_op(
1138+
return_value, a_arg, b_arg, mpz_cdiv_q, gmp_mpz_cdiv_q_ui, 1, /* is_operator */ false);
11301139
break;
11311140
case GMP_ROUND_MINUSINF:
1132-
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, gmp_mpz_fdiv_q_ui, 1);
1141+
gmp_zval_binary_ui_op(
1142+
return_value, a_arg, b_arg, mpz_fdiv_q, gmp_mpz_fdiv_q_ui, 1, /* is_operator */ false);
11331143
break;
11341144
default:
11351145
zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
@@ -1670,7 +1680,7 @@ ZEND_FUNCTION(gmp_cmp)
16701680
RETURN_THROWS();
16711681
}
16721682

1673-
gmp_cmp(return_value, a_arg, b_arg);
1683+
gmp_cmp(return_value, a_arg, b_arg, /* is_operator */ false);
16741684
}
16751685
/* }}} */
16761686

ext/gmp/tests/bug81119.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GMP operators throw errors with wrong parameter names
3+
--FILE--
4+
<?php
5+
6+
function test($f) {
7+
try {
8+
$f();
9+
echo "No error?\n";
10+
} catch (TypeError|ValueError $e) {
11+
echo $e->getMessage(), "\n";
12+
}
13+
}
14+
test(fn($WRONG_SCOPE_1 = 0, $WRONG_SCOPE_2 = 0) => gmp_init(1) < "x");
15+
test(fn($WRONG_SCOPE_1 = 0, $WRONG_SCOPE_2 = 0) => gmp_init(1) < []);
16+
test(fn($WRONG_SCOPE_1 = 0, $WRONG_SCOPE_2 = 0) => gmp_init(1) + "x");
17+
test(fn($WRONG_SCOPE_1 = 0, $WRONG_SCOPE_2 = 0) => gmp_init(1) + []);
18+
19+
?>
20+
--EXPECT--
21+
Number is not an integer string
22+
Number must be of type GMP|string|int, array given
23+
Number is not an integer string
24+
Number must be of type GMP|string|int, array given

ext/gmp/tests/comparison_invalid.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ try {
1919

2020
?>
2121
--EXPECT--
22-
ValueError: main(): Argument #2 is not an integer string
23-
TypeError: main(): Argument #2 must be of type GMP|string|int, DateTime given
22+
ValueError: Number is not an integer string
23+
TypeError: Number must be of type GMP|string|int, DateTime given

ext/gmp/tests/overloading.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ bool(false)
282282
bool(true)
283283
bool(false)
284284
bool(true)
285-
main(): Argument #2 must be of type GMP|string|int, stdClass given
285+
Number must be of type GMP|string|int, stdClass given
286286
object(GMP)#4 (1) {
287287
["num"]=>
288288
string(2) "43"

0 commit comments

Comments
 (0)