diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 4894b09afe442..b6329daeeea0e 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -586,6 +586,33 @@ ZEND_MODULE_INFO_D(gmp) } /* }}} */ +static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos) +{ + const char *num_str = ZSTR_VAL(val); + bool skip_lead = false; + + if (ZSTR_LEN(val) >= 2 && num_str[0] == '0') { + if ((base == 0 || base == 16) && (num_str[1] == 'x' || num_str[1] == 'X')) { + base = 16; + skip_lead = true; + } else if ((base == 0 || base == 2) && (num_str[1] == 'b' || num_str[1] == 'B')) { + base = 2; + skip_lead = true; + } + } + + int gmp_ret = mpz_set_str(gmp_number, (skip_lead ? &num_str[2] : num_str), (int) base); + if (-1 == gmp_ret) { + if (arg_pos == 0) { + zend_value_error("Number is not an integer string"); + } else { + zend_argument_value_error(arg_pos, "is not an integer string"); + } + return FAILURE; + } + + return SUCCESS; +} /* {{{ convert_to_gmp * 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 mpz_set_si(gmpnumber, Z_LVAL_P(val)); return SUCCESS; case IS_STRING: { - char *numstr = Z_STRVAL_P(val); - zend_bool skip_lead = 0; - int ret; - - if (Z_STRLEN_P(val) >= 2 && numstr[0] == '0') { - if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) { - base = 16; - skip_lead = 1; - } else if ((base == 0 || base == 2) && (numstr[1] == 'b' || numstr[1] == 'B')) { - base = 2; - skip_lead = 1; - } - } - - ret = mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), (int) base); - if (-1 == ret) { - if (arg_pos == 0) { - zend_value_error("Number is not an integer string"); - } else { - zend_argument_value_error(arg_pos, "is not an integer string"); - } - return FAILURE; - } - - return SUCCESS; + return convert_zstr_to_gmp(gmpnumber, Z_STR_P(val), base, arg_pos); } default: { zend_long lval; @@ -868,22 +871,29 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t /* {{{ Initializes GMP number */ ZEND_FUNCTION(gmp_init) { - zval *number_arg; - mpz_ptr gmpnumber; + mpz_ptr gmp_number; + zend_string *arg_str = NULL; + zend_long arg_l = 0; zend_long base = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &number_arg, &base) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STR_OR_LONG(arg_str, arg_l) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(base) + ZEND_PARSE_PARAMETERS_END(); if (base && (base < 2 || base > GMP_MAX_BASE)) { zend_argument_value_error(2, "must be between 2 and %d", GMP_MAX_BASE); RETURN_THROWS(); } - INIT_GMP_RETVAL(gmpnumber); - if (convert_to_gmp(gmpnumber, number_arg, base, 1) == FAILURE) { - RETURN_THROWS(); + INIT_GMP_RETVAL(gmp_number); + if (arg_str) { + if (convert_zstr_to_gmp(gmp_number, arg_str, base, 1) == FAILURE) { + RETURN_THROWS(); + } + } else { + mpz_set_si(gmp_number, arg_l); } } /* }}} */ diff --git a/ext/gmp/tests/gh9308.phpt b/ext/gmp/tests/gh9308.phpt new file mode 100644 index 0000000000000..1634308d805e0 --- /dev/null +++ b/ext/gmp/tests/gh9308.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug GH-9308: GMP throws the wrong error when a GMP object is passed to gmp_init() +--SKIPIF-- + +--FILE-- +getMessage(), \PHP_EOL; +} + +?> +--EXPECT-- +gmp_init(): Argument #1 ($num) must be of type string|int, GMP given