@@ -46,7 +46,7 @@ struct php_unserialize_data {
46
46
var_dtor_entries *first_dtor;
47
47
var_dtor_entries *last_dtor;
48
48
HashTable *allowed_classes;
49
- HashTable *refs ;
49
+ HashTable *ref_props ;
50
50
var_entries entries;
51
51
};
52
52
@@ -58,7 +58,7 @@ PHPAPI php_unserialize_data_t php_var_unserialize_init() {
58
58
d->last = &d->entries ;
59
59
d->first_dtor = d->last_dtor = NULL ;
60
60
d->allowed_classes = NULL ;
61
- d->refs = NULL ;
61
+ d->ref_props = NULL ;
62
62
d->entries .used_slots = 0 ;
63
63
d->entries .next = NULL ;
64
64
if (!BG (serialize_lock)) {
@@ -242,8 +242,8 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
242
242
243
243
zval_ptr_dtor_nogc (&wakeup_name);
244
244
245
- if ((*var_hashx)->refs ) {
246
- zend_array_destroy ((*var_hashx)->refs );
245
+ if ((*var_hashx)->ref_props ) {
246
+ zend_array_destroy ((*var_hashx)->ref_props );
247
247
}
248
248
}
249
249
@@ -497,6 +497,7 @@ string_key:
497
497
498
498
if ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL ) {
499
499
if (Z_TYPE_P (old_data) == IS_INDIRECT) {
500
+ // TODO Deduplicate with above code?
500
501
old_data = Z_INDIRECT_P (old_data);
501
502
if (Z_STRVAL (key)[0 ] == 0 ) {
502
503
zend_string *member, *class ;
@@ -515,18 +516,19 @@ string_key:
515
516
info = zend_get_property_info (ce, Z_STR (key), 1 );
516
517
}
517
518
var_push_dtor (var_hash, old_data);
518
- old_data = zend_hash_update_ind (ht, Z_STR (key), &d);
519
+ data = zend_hash_update_ind (ht, Z_STR (key), &d);
519
520
520
521
if (EXPECTED (!info->type )) {
521
522
info = NULL ;
522
- data = old_data;
523
523
} else {
524
- /* little hack to disallow references */
525
- if (!(*var_hash)->refs ) {
526
- (*var_hash)->refs = emalloc (sizeof (HashTable));
527
- zend_hash_init ((*var_hash)->refs , 8 , NULL , ZVAL_PTR_DTOR, 0 );
524
+ /* Remember to which property this slot belongs, so we can add a type
525
+ * source if it is turned into a reference lateron. */
526
+ if (!(*var_hash)->ref_props ) {
527
+ (*var_hash)->ref_props = emalloc (sizeof (HashTable));
528
+ zend_hash_init ((*var_hash)->ref_props , 8 , NULL , NULL , 0 );
528
529
}
529
- data = zend_hash_next_index_insert ((*var_hash)->refs , &d);
530
+ zend_hash_index_update_ptr (
531
+ (*var_hash)->ref_props , (zend_uintptr_t ) data, info);
530
532
}
531
533
} else {
532
534
var_push_dtor (var_hash, old_data);
@@ -551,6 +553,8 @@ string_key:
551
553
}
552
554
553
555
if (UNEXPECTED (info)) {
556
+ // TODO Throw an error instead?
557
+ // TODO Handle references correctly
554
558
ZVAL_COPY_VALUE (&tmp, data);
555
559
if (UNEXPECTED (!zend_verify_property_type (info, &tmp, 1 ))) {
556
560
zval_dtor (&key);
@@ -745,13 +749,19 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key)
745
749
return 0;
746
750
}
747
751
748
- if (Z_ISREF_P(rval_ref)) {
749
- ZVAL_COPY(rval, rval_ref);
750
- } else {
752
+ if (!Z_ISREF_P(rval_ref)) {
753
+ zend_property_info *info = NULL;
754
+ if ((*var_hash)->ref_props) {
755
+ info = zend_hash_index_find_ptr((*var_hash)->ref_props, (zend_uintptr_t) rval_ref);
756
+ }
751
757
ZVAL_NEW_REF(rval_ref, rval_ref);
752
- ZVAL_COPY(rval, rval_ref);
758
+ if (info) {
759
+ ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(rval_ref), info);
760
+ }
753
761
}
754
762
763
+ ZVAL_COPY(rval, rval_ref);
764
+
755
765
return 1;
756
766
}
757
767
0 commit comments