diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index c5e49aecbd8..2349c545d87 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -55,6 +55,7 @@ ZEND_DECLARE_MODULE_GLOBALS(gmp) static ZEND_GINIT_FUNCTION(gmp); +static ZEND_GSHUTDOWN_FUNCTION(gmp); /* {{{ gmp_module_entry */ zend_module_entry gmp_module_entry = { @@ -69,7 +70,7 @@ zend_module_entry gmp_module_entry = { PHP_GMP_VERSION, ZEND_MODULE_GLOBALS(gmp), ZEND_GINIT(gmp), - NULL, + ZEND_GSHUTDOWN(gmp), NULL, STANDARD_MODULE_PROPERTIES_EX }; @@ -179,14 +180,49 @@ if (IS_GMP(zval)) { \ gmpnumber = temp.num; \ } -#define INIT_GMP_RETVAL(gmpnumber) \ - gmp_create(return_value, &gmpnumber) - static void gmp_strval(zval *result, mpz_t gmpnum, int base); static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos); static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos); static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator); +static bool gmp_zend_parse_arg_into_mpz( + zval *arg, + mpz_ptr *destination_mpz_ptr, + uint32_t arg_num +) { + if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { + if (EXPECTED(instanceof_function(Z_OBJCE_P(arg), gmp_ce))) { + *destination_mpz_ptr = GET_GMP_FROM_ZVAL(arg); + return true; + } + return false; + } + + *destination_mpz_ptr = GMPG(zpp_arg[arg_num-1]); + if (Z_TYPE_P(arg) == IS_STRING) { + return convert_zstr_to_gmp(*destination_mpz_ptr, Z_STR_P(arg), /* base */ 0, arg_num) != FAILURE; + } + + if (Z_TYPE_P(arg) == IS_LONG) { + mpz_set_si(*destination_mpz_ptr, Z_LVAL_P(arg)); + return true; + } + return false; +} + +#define GMP_Z_PARAM_INTO_MPZ_PTR(destination_mpz_ptr) \ + Z_PARAM_PROLOGUE(0, 0); \ + if (UNEXPECTED(!gmp_zend_parse_arg_into_mpz(_arg, &destination_mpz_ptr, _i))) { \ + _error_code = ZPP_ERROR_FAILURE; \ + if (!EG(exception)) { \ + zend_argument_type_error(_i, "must be of type GMP|string|int, %s given", zend_zval_value_name(_arg)); \ + } \ + break; \ + } + +#define INIT_GMP_RETVAL(gmpnumber) \ + gmp_create(return_value, &gmpnumber) + /* * The gmp_*_op functions provide an implementation for several common types * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually @@ -591,9 +627,19 @@ static ZEND_GINIT_FUNCTION(gmp) ZEND_TSRMLS_CACHE_UPDATE(); #endif gmp_globals->rand_initialized = 0; + mpz_init(gmp_globals->zpp_arg[0]); + mpz_init(gmp_globals->zpp_arg[1]); + mpz_init(gmp_globals->zpp_arg[2]); } /* }}} */ +static ZEND_GSHUTDOWN_FUNCTION(gmp) +{ + mpz_clear(gmp_globals->zpp_arg[0]); + mpz_clear(gmp_globals->zpp_arg[1]); + mpz_clear(gmp_globals->zpp_arg[2]); +} + /* {{{ ZEND_MINIT_FUNCTION */ ZEND_MINIT_FUNCTION(gmp) { diff --git a/ext/gmp/php_gmp.h b/ext/gmp/php_gmp.h index 1c03a6ee8ce..597c7a9146c 100644 --- a/ext/gmp/php_gmp.h +++ b/ext/gmp/php_gmp.h @@ -32,6 +32,7 @@ ZEND_MODULE_INFO_D(gmp); ZEND_BEGIN_MODULE_GLOBALS(gmp) bool rand_initialized; gmp_randstate_t rand_state; + mpz_t zpp_arg[3]; ZEND_END_MODULE_GLOBALS(gmp) #define GMPG(v) ZEND_MODULE_GLOBALS_ACCESSOR(gmp, v)