Skip to content

Commit 17ceed9

Browse files
committed
Implement __serialize() and __unserialize() on GMP
GMP directly implements internal serialize/unserialize handlers rather than going through the Serializable interface, so it ended up being missed when adding the new __serialize()/__unserialize() methods to other classes. The serialization format is similar to before, but uses hex instead of decimal encoding and omits the members if not used (which should be almost always).
1 parent 3ec55d6 commit 17ceed9

File tree

4 files changed

+90
-3
lines changed

4 files changed

+90
-3
lines changed

ext/gmp/gmp.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,3 +2017,48 @@ ZEND_FUNCTION(gmp_scan1)
20172017
FREE_GMP_TEMP(temp_a);
20182018
}
20192019
/* }}} */
2020+
2021+
ZEND_METHOD(GMP, __serialize)
2022+
{
2023+
ZEND_PARSE_PARAMETERS_NONE();
2024+
2025+
zval zv;
2026+
array_init(return_value);
2027+
2028+
mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(ZEND_THIS);
2029+
gmp_strval(&zv, gmpnum, 16);
2030+
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &zv);
2031+
2032+
HashTable *props = Z_OBJ_P(ZEND_THIS)->properties;
2033+
if (props && zend_hash_num_elements(props) != 0) {
2034+
ZVAL_ARR(&zv, zend_proptable_to_symtable(
2035+
zend_std_get_properties(Z_OBJ_P(ZEND_THIS)), /* always duplicate */ 1));
2036+
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &zv);
2037+
}
2038+
}
2039+
2040+
ZEND_METHOD(GMP, __unserialize)
2041+
{
2042+
HashTable *data;
2043+
2044+
ZEND_PARSE_PARAMETERS_START(1, 1)
2045+
Z_PARAM_ARRAY_HT(data)
2046+
ZEND_PARSE_PARAMETERS_END();
2047+
2048+
zval *num = zend_hash_index_find(data, 0);
2049+
if (!num || Z_TYPE_P(num) != IS_STRING ||
2050+
convert_to_gmp(GET_GMP_FROM_ZVAL(ZEND_THIS), num, 16, 0) == FAILURE) {
2051+
zend_throw_exception(NULL, "Could not unserialize number", 0);
2052+
RETURN_THROWS();
2053+
}
2054+
2055+
zval *props = zend_hash_index_find(data, 1);
2056+
if (props) {
2057+
if (Z_TYPE_P(props) != IS_ARRAY) {
2058+
zend_throw_exception(NULL, "Could not unserialize properties", 0);
2059+
RETURN_THROWS();
2060+
}
2061+
2062+
object_properties_load(Z_OBJ_P(ZEND_THIS), Z_ARRVAL_P(props));
2063+
}
2064+
}

ext/gmp/gmp.stub.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
class GMP
66
{
7+
public function __serialize(): array {}
8+
9+
public function __unserialize(array $data): void {}
710
}
811

912
function gmp_init(int|string $num, int $base = 0): GMP {}

ext/gmp/gmp_arginfo.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 05e618ec428bd8769410153469c42cbc923ea77f */
2+
* Stub hash: be077a57bc9ddbb9100fadfb212857c0b8f21ebf */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_init, 0, 1, GMP, 0)
55
ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_STRING, NULL)
@@ -184,6 +184,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_binomial, 0, 2, GMP, 0)
184184
ZEND_ARG_TYPE_INFO(0, k, IS_LONG, 0)
185185
ZEND_END_ARG_INFO()
186186

187+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_GMP___serialize, 0, 0, IS_ARRAY, 0)
188+
ZEND_END_ARG_INFO()
189+
190+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_GMP___unserialize, 0, 1, IS_VOID, 0)
191+
ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0)
192+
ZEND_END_ARG_INFO()
193+
187194

188195
ZEND_FUNCTION(gmp_init);
189196
ZEND_FUNCTION(gmp_import);
@@ -235,6 +242,8 @@ ZEND_FUNCTION(gmp_popcount);
235242
ZEND_FUNCTION(gmp_hamdist);
236243
ZEND_FUNCTION(gmp_nextprime);
237244
ZEND_FUNCTION(gmp_binomial);
245+
ZEND_METHOD(GMP, __serialize);
246+
ZEND_METHOD(GMP, __unserialize);
238247

239248

240249
static const zend_function_entry ext_functions[] = {
@@ -294,6 +303,8 @@ static const zend_function_entry ext_functions[] = {
294303

295304

296305
static const zend_function_entry class_GMP_methods[] = {
306+
ZEND_ME(GMP, __serialize, arginfo_class_GMP___serialize, ZEND_ACC_PUBLIC)
307+
ZEND_ME(GMP, __unserialize, arginfo_class_GMP___unserialize, ZEND_ACC_PUBLIC)
297308
ZEND_FE_END
298309
};
299310

ext/gmp/tests/serialize.phpt

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ var_dump(unserialize($s));
1111

1212
$n = gmp_init(13);
1313
$n->foo = "bar";
14-
var_dump(unserialize(serialize($n)));
14+
var_dump($s = serialize($n));
15+
var_dump(unserialize($s));
16+
17+
var_dump(unserialize('C:3:"GMP":15:{s:2:"42";a:0:{}}'));
1518

1619
try {
1720
unserialize('C:3:"GMP":0:{}');
@@ -21,22 +24,47 @@ try {
2124
unserialize('C:3:"GMP":9:{s:2:"42";}');
2225
} catch (Exception $e) { var_dump($e->getMessage()); }
2326

27+
try {
28+
unserialize('O:3:"GMP":0:{}');
29+
} catch (Exception $e) { var_dump($e->getMessage()); }
30+
31+
try {
32+
unserialize('O:3:"GMP":1:{i:0;i:0;}');
33+
} catch (Exception $e) { var_dump($e->getMessage()); }
34+
35+
try {
36+
unserialize('O:3:"GMP":1:{i:0;s:0:"";}');
37+
} catch (Exception $e) { var_dump($e->getMessage()); }
38+
39+
try {
40+
unserialize('O:3:"GMP":2:{i:0;s:1:"0";i:1;i:0;}');
41+
} catch (Exception $e) { var_dump($e->getMessage()); }
42+
2443
?>
2544
--EXPECTF--
2645
object(GMP)#%d (1) {
2746
["num"]=>
2847
string(2) "42"
2948
}
30-
string(30) "C:3:"GMP":15:{s:2:"42";a:0:{}}"
49+
string(27) "O:3:"GMP":1:{i:0;s:2:"2a";}"
3150
object(GMP)#%d (1) {
3251
["num"]=>
3352
string(2) "42"
3453
}
54+
string(56) "O:3:"GMP":2:{i:0;s:1:"d";i:1;a:1:{s:3:"foo";s:3:"bar";}}"
3555
object(GMP)#%d (2) {
3656
["foo"]=>
3757
string(3) "bar"
3858
["num"]=>
3959
string(2) "13"
4060
}
61+
object(GMP)#1 (1) {
62+
["num"]=>
63+
string(2) "42"
64+
}
65+
string(28) "Could not unserialize number"
66+
string(32) "Could not unserialize properties"
67+
string(28) "Could not unserialize number"
68+
string(28) "Could not unserialize number"
4169
string(28) "Could not unserialize number"
4270
string(32) "Could not unserialize properties"

0 commit comments

Comments
 (0)