Implement GMP::__construct()

Implements a proper constructor for GMP as discussed in both GH-10158 and https://externals.io/message/119216.
Fixes GH-10155

Closes GH-10225

Signed-off-by: George Peter Banyard <girgias@php.net>
This commit is contained in:
Niels Dossche 2023-01-05 00:28:36 +01:00 committed by George Peter Banyard
parent 148ac364e9
commit 4ea85d4044
No known key found for this signature in database
GPG Key ID: 3306078E3194AEBD
6 changed files with 116 additions and 9 deletions

3
NEWS
View File

@ -5,6 +5,9 @@ PHP NEWS
- Core:
. Fixed incorrect check condition in ZEND_YIELD. (nielsdos)
- GMP:
. Properly implement GMP::__construct(). (nielsdos)
02 Feb 2023, PHP 8.2.2
- Core:

View File

@ -104,6 +104,10 @@ PHP 8.2 UPGRADE NOTES
flags to determine if it should create a sub directory or not when creating
a database file.
- GMP:
. GMP::__construct() can now be used instead of gmp_init() to initialize an object (Only as of PHP 8.2.3)
- OCI8:
. Added an oci8.prefetch_lob_size directive and oci_set_prefetch_lob()
function to tune LOB query performance by reducing the number of

View File

@ -862,6 +862,26 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t
}
/* }}} */
static bool gmp_verify_base(zend_long base, uint32_t arg_num)
{
if (base && (base < 2 || base > GMP_MAX_BASE)) {
zend_argument_value_error(arg_num, "must be between 2 and %d", GMP_MAX_BASE);
return false;
}
return true;
}
static zend_result gmp_initialize_number(mpz_ptr gmp_number, const zend_string *arg_str, zend_long arg_l, zend_long base)
{
if (arg_str) {
return convert_zstr_to_gmp(gmp_number, arg_str, base, 1);
}
mpz_set_si(gmp_number, arg_l);
return SUCCESS;
}
/* {{{ Initializes GMP number */
ZEND_FUNCTION(gmp_init)
{
@ -876,18 +896,14 @@ ZEND_FUNCTION(gmp_init)
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);
if (!gmp_verify_base(base, 2)) {
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);
if (gmp_initialize_number(gmp_number, arg_str, arg_l, base) == FAILURE) {
RETURN_THROWS();
}
}
/* }}} */
@ -2021,6 +2037,30 @@ ZEND_FUNCTION(gmp_scan1)
}
/* }}} */
ZEND_METHOD(GMP, __construct)
{
zend_string *arg_str = NULL;
zend_long arg_l = 0;
zend_long base = 0;
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_LONG(arg_str, arg_l)
Z_PARAM_LONG(base)
ZEND_PARSE_PARAMETERS_END();
if (!gmp_verify_base(base, 2)) {
RETURN_THROWS();
}
return_value = ZEND_THIS;
mpz_ptr gmp_number = GET_GMP_FROM_ZVAL(ZEND_THIS);
if (gmp_initialize_number(gmp_number, arg_str, arg_l, base) == FAILURE) {
RETURN_THROWS();
}
}
ZEND_METHOD(GMP, __serialize)
{
ZEND_PARSE_PARAMETERS_NONE();

View File

@ -59,6 +59,8 @@ const GMP_NATIVE_ENDIAN = UNKNOWN;
class GMP
{
public function __construct(int|string $num = 0, int $base = 0) {}
public function __serialize(): array {}
public function __unserialize(array $data): void {}

9
ext/gmp/gmp_arginfo.h generated
View File

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 64a40a366b87a96a291de6a474e60c8d98d15da1 */
* Stub hash: d52f82c7084a8122fe07c91eb6d4ab6030daa27d */
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_init, 0, 1, GMP, 0)
ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_STRING, NULL)
@ -184,6 +184,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_binomial, 0, 2, GMP, 0)
ZEND_ARG_TYPE_INFO(0, k, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_GMP___construct, 0, 0, 0)
ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_STRING, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, base, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_GMP___serialize, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
@ -242,6 +247,7 @@ ZEND_FUNCTION(gmp_popcount);
ZEND_FUNCTION(gmp_hamdist);
ZEND_FUNCTION(gmp_nextprime);
ZEND_FUNCTION(gmp_binomial);
ZEND_METHOD(GMP, __construct);
ZEND_METHOD(GMP, __serialize);
ZEND_METHOD(GMP, __unserialize);
@ -303,6 +309,7 @@ static const zend_function_entry ext_functions[] = {
static const zend_function_entry class_GMP_methods[] = {
ZEND_ME(GMP, __construct, arginfo_class_GMP___construct, ZEND_ACC_PUBLIC)
ZEND_ME(GMP, __serialize, arginfo_class_GMP___serialize, ZEND_ACC_PUBLIC)
ZEND_ME(GMP, __unserialize, arginfo_class_GMP___unserialize, ZEND_ACC_PUBLIC)
ZEND_FE_END

View File

@ -0,0 +1,51 @@
--TEST--
Constructor for GMP
--EXTENSIONS--
gmp
--FILE--
<?php
var_dump(new GMP);
var_dump(new GMP(0));
var_dump(new GMP(123));
var_dump(new GMP("0xAA"));
var_dump(new GMP("12", 4));
try {
var_dump(new GMP("12", 999));
} catch (ValueError $e) {
echo $e->getMessage() . "\n";
}
try {
var_dump(new GMP("", 10));
} catch (ValueError $e) {
echo $e->getMessage() . "\n";
}
try {
var_dump(new GMP("hello"));
} catch (ValueError $e) {
echo $e->getMessage() . "\n";
}
?>
--EXPECT--
object(GMP)#1 (1) {
["num"]=>
string(1) "0"
}
object(GMP)#1 (1) {
["num"]=>
string(1) "0"
}
object(GMP)#1 (1) {
["num"]=>
string(3) "123"
}
object(GMP)#1 (1) {
["num"]=>
string(3) "170"
}
object(GMP)#1 (1) {
["num"]=>
string(1) "6"
}
GMP::__construct(): Argument #2 ($base) must be between 2 and 62
GMP::__construct(): Argument #1 ($num) is not an integer string
GMP::__construct(): Argument #1 ($num) is not an integer string