Skip to content

Commit 293e691

Browse files
committed
Fix GH-9308 GMP throws the wrong error when a GMP object is passed to gmp_init()
Closes GH-9490
1 parent d0b3096 commit 293e691

File tree

3 files changed

+66
-33
lines changed

3 files changed

+66
-33
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ PHP NEWS
2020
. Fixed bug #77780 ("Headers already sent..." when previous connection was
2121
aborted). (Jakub Zelenka)
2222

23+
- GMP
24+
. Fixed bug GH-9308 (GMP throws the wrong error when a GMP object is passed
25+
to gmp_init()). (Girgias)
26+
2327
- PDO_PGSQL:
2428
. Fixed bug GH-9411 (PgSQL large object resource is incorrectly closed).
2529
(Yurunsoft)

ext/gmp/gmp.c

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,33 @@ ZEND_MODULE_INFO_D(gmp)
586586
}
587587
/* }}} */
588588

589+
static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos)
590+
{
591+
const char *num_str = ZSTR_VAL(val);
592+
bool skip_lead = false;
593+
594+
if (ZSTR_LEN(val) >= 2 && num_str[0] == '0') {
595+
if ((base == 0 || base == 16) && (num_str[1] == 'x' || num_str[1] == 'X')) {
596+
base = 16;
597+
skip_lead = true;
598+
} else if ((base == 0 || base == 2) && (num_str[1] == 'b' || num_str[1] == 'B')) {
599+
base = 2;
600+
skip_lead = true;
601+
}
602+
}
603+
604+
int gmp_ret = mpz_set_str(gmp_number, (skip_lead ? &num_str[2] : num_str), (int) base);
605+
if (-1 == gmp_ret) {
606+
if (arg_pos == 0) {
607+
zend_value_error("Number is not an integer string");
608+
} else {
609+
zend_argument_value_error(arg_pos, "is not an integer string");
610+
}
611+
return FAILURE;
612+
}
613+
614+
return SUCCESS;
615+
}
589616

590617
/* {{{ convert_to_gmp
591618
* Convert zval to be gmp number */
@@ -596,31 +623,7 @@ static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, ui
596623
mpz_set_si(gmpnumber, Z_LVAL_P(val));
597624
return SUCCESS;
598625
case IS_STRING: {
599-
char *numstr = Z_STRVAL_P(val);
600-
zend_bool skip_lead = 0;
601-
int ret;
602-
603-
if (Z_STRLEN_P(val) >= 2 && numstr[0] == '0') {
604-
if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) {
605-
base = 16;
606-
skip_lead = 1;
607-
} else if ((base == 0 || base == 2) && (numstr[1] == 'b' || numstr[1] == 'B')) {
608-
base = 2;
609-
skip_lead = 1;
610-
}
611-
}
612-
613-
ret = mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), (int) base);
614-
if (-1 == ret) {
615-
if (arg_pos == 0) {
616-
zend_value_error("Number is not an integer string");
617-
} else {
618-
zend_argument_value_error(arg_pos, "is not an integer string");
619-
}
620-
return FAILURE;
621-
}
622-
623-
return SUCCESS;
626+
return convert_zstr_to_gmp(gmpnumber, Z_STR_P(val), base, arg_pos);
624627
}
625628
default: {
626629
zend_long lval;
@@ -868,22 +871,29 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t
868871
/* {{{ Initializes GMP number */
869872
ZEND_FUNCTION(gmp_init)
870873
{
871-
zval *number_arg;
872-
mpz_ptr gmpnumber;
874+
mpz_ptr gmp_number;
875+
zend_string *arg_str = NULL;
876+
zend_long arg_l = 0;
873877
zend_long base = 0;
874878

875-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &number_arg, &base) == FAILURE) {
876-
RETURN_THROWS();
877-
}
879+
ZEND_PARSE_PARAMETERS_START(1, 2)
880+
Z_PARAM_STR_OR_LONG(arg_str, arg_l)
881+
Z_PARAM_OPTIONAL
882+
Z_PARAM_LONG(base)
883+
ZEND_PARSE_PARAMETERS_END();
878884

879885
if (base && (base < 2 || base > GMP_MAX_BASE)) {
880886
zend_argument_value_error(2, "must be between 2 and %d", GMP_MAX_BASE);
881887
RETURN_THROWS();
882888
}
883889

884-
INIT_GMP_RETVAL(gmpnumber);
885-
if (convert_to_gmp(gmpnumber, number_arg, base, 1) == FAILURE) {
886-
RETURN_THROWS();
890+
INIT_GMP_RETVAL(gmp_number);
891+
if (arg_str) {
892+
if (convert_zstr_to_gmp(gmp_number, arg_str, base, 1) == FAILURE) {
893+
RETURN_THROWS();
894+
}
895+
} else {
896+
mpz_set_si(gmp_number, arg_l);
887897
}
888898
}
889899
/* }}} */

ext/gmp/tests/gh9308.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Bug GH-9308: GMP throws the wrong error when a GMP object is passed to gmp_init()
3+
--SKIPIF--
4+
<?php extension_loaded('gmp') or die('skip gmp extension is not available'); ?>
5+
--FILE--
6+
<?php
7+
declare(strict_types=1);
8+
9+
/* We need strict_types as GMP has a __toString() handler */
10+
11+
try {
12+
$gmp = gmp_init(gmp_init(123));
13+
} catch (\TypeError $e) {
14+
echo $e->getMessage(), \PHP_EOL;
15+
}
16+
17+
?>
18+
--EXPECT--
19+
gmp_init(): Argument #1 ($num) must be of type string|int, GMP given

0 commit comments

Comments
 (0)