@@ -142,6 +142,17 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval)
142
142
}
143
143
}
144
144
145
+ static zend_never_inline void var_push_dtor_value (php_unserialize_data_t *var_hashx, zval *rval)
146
+ {
147
+ if (Z_REFCOUNTED_P (rval)) {
148
+ zval *tmp_var = var_tmp_var (var_hashx);
149
+ if (!tmp_var) {
150
+ return ;
151
+ }
152
+ ZVAL_COPY_VALUE (tmp_var, rval);
153
+ }
154
+ }
155
+
145
156
static zend_always_inline zval *tmp_var (php_unserialize_data_t *var_hashx, zend_long num)
146
157
{
147
158
var_dtor_entries *var_hash;
@@ -451,7 +462,7 @@ static inline size_t parse_uiv(const unsigned char *p)
451
462
#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash
452
463
#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash
453
464
454
- static int php_var_unserialize_internal (UNSERIALIZE_PARAMETER, int as_key );
465
+ static int php_var_unserialize_internal (UNSERIALIZE_PARAMETER);
455
466
456
467
static zend_always_inline int process_nested_array_data (UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements)
457
468
{
@@ -468,54 +479,43 @@ static zend_always_inline int process_nested_array_data(UNSERIALIZE_PARAMETER, H
468
479
}
469
480
470
481
while (elements-- > 0 ) {
471
- zval key, *data, d, *old_data ;
482
+ zval key, *data;
472
483
zend_ulong idx;
473
484
474
485
ZVAL_UNDEF (&key);
475
486
476
- if (!php_var_unserialize_internal (&key, p, max, NULL , 1 )) {
487
+ if (!php_var_unserialize_internal (&key, p, max, NULL )) {
477
488
zval_ptr_dtor (&key);
478
489
goto failure;
479
490
}
480
491
481
- data = NULL ;
482
- ZVAL_UNDEF (&d);
483
-
484
492
if (Z_TYPE (key) == IS_LONG) {
485
493
idx = Z_LVAL (key);
486
494
numeric_key:
487
- if (UNEXPECTED ((old_data = zend_hash_index_find (ht, idx)) != NULL )) {
488
- // ??? update hash
489
- var_push_dtor (var_hash, old_data);
490
- data = zend_hash_index_update (ht, idx, &d);
491
- } else {
492
- data = zend_hash_index_add_new (ht, idx, &d);
495
+ data = zend_hash_index_lookup (ht, idx);
496
+ if (UNEXPECTED (Z_TYPE_INFO_P (data) != IS_NULL)) {
497
+ var_push_dtor_value (var_hash, data);
498
+ ZVAL_NULL (data);
493
499
}
494
500
} else if (Z_TYPE (key) == IS_STRING) {
495
501
if (UNEXPECTED (ZEND_HANDLE_NUMERIC (Z_STR (key), idx))) {
496
502
goto numeric_key;
497
503
}
498
- if (UNEXPECTED ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL )) {
499
- // ??? update hash
500
- var_push_dtor (var_hash, old_data);
501
- data = zend_hash_update (ht, Z_STR (key), &d);
502
- } else {
503
- data = zend_hash_add_new (ht, Z_STR (key), &d);
504
+ data = zend_hash_lookup (ht, Z_STR (key));
505
+ if (UNEXPECTED (Z_TYPE_INFO_P (data) != IS_NULL)) {
506
+ var_push_dtor_value (var_hash, data);
507
+ ZVAL_NULL (data);
504
508
}
505
509
} else {
506
510
zval_ptr_dtor (&key);
507
511
goto failure;
508
512
}
509
513
510
- if (!php_var_unserialize_internal (data, p, max, var_hash, 0 )) {
511
- zval_ptr_dtor (&key);
512
- goto failure;
513
- }
514
+ zval_ptr_dtor_str (&key);
514
515
515
- if (BG (unserialize). level > 1 ) {
516
- var_push_dtor (var_hash, data) ;
516
+ if (! php_var_unserialize_internal (data, p, max, var_hash) ) {
517
+ goto failure ;
517
518
}
518
- zval_ptr_dtor_str (&key);
519
519
520
520
if (elements && *(*p-1 ) != ' ;' && *(*p-1 ) != ' }' ) {
521
521
(*p)--;
@@ -587,49 +587,45 @@ static zend_always_inline int process_nested_object_data(UNSERIALIZE_PARAMETER,
587
587
}
588
588
589
589
while (elements-- > 0 ) {
590
- zval key, *data, d, *old_data ;
590
+ zval key, *data;
591
591
zend_property_info *info = NULL ;
592
592
593
593
ZVAL_UNDEF (&key);
594
594
595
- if (!php_var_unserialize_internal (&key, p, max, NULL , 1 )) {
595
+ if (!php_var_unserialize_internal (&key, p, max, NULL )) {
596
596
zval_ptr_dtor (&key);
597
597
goto failure;
598
598
}
599
599
600
- data = NULL ;
601
- ZVAL_UNDEF (&d);
602
-
603
600
if (EXPECTED (Z_TYPE (key) == IS_STRING)) {
604
601
string_key:
605
- if ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL ) {
606
- if (Z_TYPE_P (old_data) == IS_INDIRECT) {
602
+ data = zend_hash_find (ht, Z_STR (key));
603
+ if (data != NULL ) {
604
+ if (Z_TYPE_P (data) == IS_INDIRECT) {
607
605
declared_property:
608
606
/* This is a property with a declaration */
609
- old_data = Z_INDIRECT_P (old_data );
610
- info = zend_get_typed_property_info_for_slot (obj, old_data );
607
+ data = Z_INDIRECT_P (data );
608
+ info = zend_get_typed_property_info_for_slot (obj, data );
611
609
if (info) {
612
- if (Z_ISREF_P (old_data )) {
610
+ if (Z_ISREF_P (data )) {
613
611
/* If the value is overwritten, remove old type source from ref. */
614
- ZEND_REF_DEL_TYPE_SOURCE (Z_REF_P (old_data ), info);
612
+ ZEND_REF_DEL_TYPE_SOURCE (Z_REF_P (data ), info);
615
613
}
616
614
617
615
if ((*var_hash)->ref_props ) {
618
616
/* Remove old entry from ref_props table, if it exists. */
619
617
zend_hash_index_del (
620
- (*var_hash)->ref_props , (zend_uintptr_t ) old_data );
618
+ (*var_hash)->ref_props , (zend_uintptr_t ) data );
621
619
}
622
620
}
623
- var_push_dtor (var_hash, old_data);
624
- Z_TRY_DELREF_P (old_data);
625
- ZVAL_UNDEF (old_data);
626
- data = old_data;
621
+ var_push_dtor_value (var_hash, data);
622
+ ZVAL_NULL (data);
627
623
} else {
628
624
int ret = is_property_visibility_changed (obj->ce , &key);
629
625
630
626
if (EXPECTED (!ret)) {
631
- var_push_dtor (var_hash, old_data );
632
- data = zend_hash_update (ht, Z_STR (key), &d );
627
+ var_push_dtor_value (var_hash, data );
628
+ ZVAL_NULL (data );
633
629
} else if (ret < 0 ) {
634
630
goto failure;
635
631
} else {
@@ -640,20 +636,17 @@ declared_property:
640
636
int ret = is_property_visibility_changed (obj->ce , &key);
641
637
642
638
if (EXPECTED (!ret)) {
643
- data = zend_hash_add_new (ht, Z_STR (key), &d );
639
+ data = zend_hash_add_new (ht, Z_STR (key), &EG (uninitialized_zval) );
644
640
} else if (ret < 0 ) {
645
641
goto failure;
646
642
} else {
647
643
second_try:
648
- if ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL ) {
649
- if (Z_TYPE_P (old_data) == IS_INDIRECT) {
650
- goto declared_property;
651
- } else {
652
- var_push_dtor (var_hash, old_data);
653
- data = zend_hash_update (ht, Z_STR (key), &d);
654
- }
655
- } else {
656
- data = zend_hash_add_new (ht, Z_STR (key), &d);
644
+ data = zend_hash_lookup (ht, Z_STR (key));
645
+ if (Z_TYPE_P (data) == IS_INDIRECT) {
646
+ goto declared_property;
647
+ } else if (UNEXPECTED (Z_TYPE_P (data) != IS_NULL)) {
648
+ var_push_dtor_value (var_hash, data);
649
+ ZVAL_NULL (data);
657
650
}
658
651
}
659
652
}
@@ -667,7 +660,7 @@ second_try:
667
660
goto failure;
668
661
}
669
662
670
- if (!php_var_unserialize_internal (data, p, max, var_hash, 0 )) {
663
+ if (!php_var_unserialize_internal (data, p, max, var_hash)) {
671
664
if (info && Z_ISREF_P (data)) {
672
665
/* Add type source even if we failed to unserialize.
673
666
* The data is still stored in the property. */
@@ -697,10 +690,6 @@ second_try:
697
690
}
698
691
}
699
692
700
- if (BG (unserialize).level > 1 ) {
701
- var_push_dtor (var_hash, data);
702
- }
703
-
704
693
if (elements && *(*p-1 ) != ' ;' && *(*p-1 ) != ' }' ) {
705
694
(*p)--;
706
695
goto failure;
@@ -834,7 +823,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
834
823
zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0 ;
835
824
int result;
836
825
837
- result = php_var_unserialize_internal (UNSERIALIZE_PASSTHRU, 0 );
826
+ result = php_var_unserialize_internal (UNSERIALIZE_PASSTHRU);
838
827
839
828
if (!result) {
840
829
/* If the unserialization failed, mark all elements that have been added to var_hash
@@ -855,7 +844,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
855
844
return result;
856
845
}
857
846
858
- static int php_var_unserialize_internal (UNSERIALIZE_PARAMETER, int as_key )
847
+ static int php_var_unserialize_internal (UNSERIALIZE_PARAMETER)
859
848
{
860
849
const unsigned char *cursor, *limit, *marker, *start;
861
850
zval *rval_ref;
@@ -886,7 +875,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key)
886
875
return 0;
887
876
}
888
877
889
- if (Z_ISUNDEF_P( rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P( Z_REFVAL_P(rval_ref)) )) {
878
+ if (rval_ref == rval || (Z_ISREF_P(rval_ref) && Z_REFVAL_P(rval_ref) == rval )) {
890
879
return 0;
891
880
}
892
881
@@ -1028,7 +1017,8 @@ use_double:
1028
1017
YYCURSOR += 2;
1029
1018
*p = YYCURSOR;
1030
1019
1031
- if (as_key) {
1020
+ if (!var_hash) {
1021
+ /* Array or object key unserialization */
1032
1022
ZVAL_STR(rval, zend_string_init_interned(str, len, 0));
1033
1023
} else {
1034
1024
ZVAL_STRINGL_FAST(rval, str, len);
0 commit comments