diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-02-21 12:04:49 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-02-21 12:04:49 +0100 |
commit | af324e24df85022314787f6dcf2ac811f58b88f3 (patch) | |
tree | d62217bcb5ee06674100425d8ef9b75738d2ffcf | |
parent | b3e0e555c8936a123f0e5c44f8ba0667becb4357 (diff) | |
download | php-git-af324e24df85022314787f6dcf2ac811f58b88f3.tar.gz |
Fix issue mentioned in #77302
Apparently Serializable::serialize() can return NULL, which is encoded
as N;. As we do not allow back-references to non-object values in
PHP 7.3 we need to make sure that any references are also compiled to
N;.
-rw-r--r-- | ext/standard/tests/serialize/ref_to_failed_serialize.phpt | 28 | ||||
-rw-r--r-- | ext/standard/var.c | 10 |
2 files changed, 37 insertions, 1 deletions
diff --git a/ext/standard/tests/serialize/ref_to_failed_serialize.phpt b/ext/standard/tests/serialize/ref_to_failed_serialize.phpt new file mode 100644 index 0000000000..c69c888132 --- /dev/null +++ b/ext/standard/tests/serialize/ref_to_failed_serialize.phpt @@ -0,0 +1,28 @@ +--TEST-- +References to objects for which Serializable::serialize() returned NULL should use N; +--FILE-- +<?php + +class NotSerializable implements Serializable { + public function serialize() { + return null; + } + + public function unserialize($serialized) { + } +} + +$obj = new NotSerializable(); +$data = [$obj, $obj]; +var_dump($s = serialize($data)); +var_dump(unserialize($s)); + +?> +--EXPECT-- +string(18) "a:2:{i:0;N;i:1;N;}" +array(2) { + [0]=> + NULL + [1]=> + NULL +} diff --git a/ext/standard/var.c b/ext/standard/var.c index 77b290a6cc..0df1e24853 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -822,7 +822,11 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_ } if (var_hash && (var_already = php_add_var_hash(var_hash, struc))) { - if (Z_ISREF_P(struc)) { + if (var_already == -1) { + /* Reference to an object that failed to serialize, replace with null. */ + smart_str_appendl(buf, "N;", 2); + return; + } else if (Z_ISREF_P(struc)) { smart_str_appendl(buf, "R:", 2); smart_str_append_long(buf, var_already); smart_str_appendc(buf, ';'); @@ -886,6 +890,10 @@ again: smart_str_appendl(buf, (char *) serialized_data, serialized_length); smart_str_appendc(buf, '}'); } else { + /* Mark this value in the var_hash, to avoid creating references to it. */ + zval *var_idx = zend_hash_index_find(&var_hash->ht, + (zend_ulong) (zend_uintptr_t) Z_COUNTED_P(struc)); + ZVAL_LONG(var_idx, -1); smart_str_appendl(buf, "N;", 2); } if (serialized_data) { |