@@ -450,7 +450,7 @@ static inline size_t parse_uiv(const unsigned char *p)
450
450
451
451
static int php_var_unserialize_internal (UNSERIALIZE_PARAMETER, int as_key);
452
452
453
- static zend_always_inline int process_nested_data (UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj )
453
+ static zend_always_inline int process_nested_array_data (UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements)
454
454
{
455
455
if (var_hash) {
456
456
if ((*var_hash)->max_depth > 0 && (*var_hash)->cur_depth >= (*var_hash)->max_depth ) {
@@ -467,7 +467,6 @@ static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTab
467
467
while (elements-- > 0 ) {
468
468
zval key, *data, d, *old_data;
469
469
zend_ulong idx;
470
- zend_property_info *info = NULL ;
471
470
472
471
ZVAL_UNDEF (&key);
473
472
@@ -479,118 +478,196 @@ static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTab
479
478
data = NULL ;
480
479
ZVAL_UNDEF (&d);
481
480
482
- if (!obj) {
483
- if (Z_TYPE (key) == IS_LONG) {
484
- idx = Z_LVAL (key);
481
+ if (Z_TYPE (key) == IS_LONG) {
482
+ idx = Z_LVAL (key);
485
483
numeric_key:
486
- if (UNEXPECTED ((old_data = zend_hash_index_find (ht, idx)) != NULL )) {
487
- // ??? update hash
488
- var_push_dtor (var_hash, old_data);
489
- data = zend_hash_index_update (ht, idx, &d);
490
- } else {
491
- data = zend_hash_index_add_new (ht, idx, &d);
492
- }
493
- } else if (Z_TYPE (key) == IS_STRING) {
494
- if (UNEXPECTED (ZEND_HANDLE_NUMERIC (Z_STR (key), idx))) {
495
- goto numeric_key;
496
- }
497
- if (UNEXPECTED ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL )) {
498
- // ??? update hash
499
- var_push_dtor (var_hash, old_data);
500
- data = zend_hash_update (ht, Z_STR (key), &d);
501
- } else {
502
- data = zend_hash_add_new (ht, Z_STR (key), &d);
503
- }
484
+ if (UNEXPECTED ((old_data = zend_hash_index_find (ht, idx)) != NULL )) {
485
+ // ??? update hash
486
+ var_push_dtor (var_hash, old_data);
487
+ data = zend_hash_index_update (ht, idx, &d);
504
488
} else {
505
- zval_ptr_dtor (&key);
506
- goto failure;
489
+ data = zend_hash_index_add_new (ht, idx, &d);
490
+ }
491
+ } else if (Z_TYPE (key) == IS_STRING) {
492
+ if (UNEXPECTED (ZEND_HANDLE_NUMERIC (Z_STR (key), idx))) {
493
+ goto numeric_key;
494
+ }
495
+ if (UNEXPECTED ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL )) {
496
+ // ??? update hash
497
+ var_push_dtor (var_hash, old_data);
498
+ data = zend_hash_update (ht, Z_STR (key), &d);
499
+ } else {
500
+ data = zend_hash_add_new (ht, Z_STR (key), &d);
501
+ }
502
+ } else {
503
+ zval_ptr_dtor (&key);
504
+ goto failure;
505
+ }
506
+
507
+ if (!php_var_unserialize_internal (data, p, max, var_hash, 0 )) {
508
+ zval_ptr_dtor (&key);
509
+ goto failure;
510
+ }
511
+
512
+ if (BG (unserialize).level > 1 ) {
513
+ var_push_dtor (var_hash, data);
514
+ }
515
+ zval_ptr_dtor_str (&key);
516
+
517
+ if (elements && *(*p-1 ) != ' ;' && *(*p-1 ) != ' }' ) {
518
+ (*p)--;
519
+ goto failure;
520
+ }
521
+ }
522
+
523
+ if (var_hash) {
524
+ (*var_hash)->cur_depth --;
525
+ }
526
+ return 1 ;
527
+
528
+ failure:
529
+ if (var_hash) {
530
+ (*var_hash)->cur_depth --;
531
+ }
532
+ return 0 ;
533
+ }
534
+
535
+ static int is_property_visibility_changed (zend_class_entry *ce, zval *key)
536
+ {
537
+ if (zend_hash_num_elements (&ce->properties_info ) > 0 ) {
538
+ zend_property_info *existing_propinfo;
539
+ const char *unmangled_class = NULL ;
540
+ const char *unmangled_prop;
541
+ size_t unmangled_prop_len;
542
+
543
+ if (UNEXPECTED (zend_unmangle_property_name_ex (Z_STR_P (key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
544
+ zval_ptr_dtor_str (key);
545
+ return -1 ;
546
+ }
547
+
548
+ if (unmangled_class == NULL ) {
549
+ existing_propinfo = zend_hash_find_ptr (&ce->properties_info , Z_STR_P (key));
550
+ if (existing_propinfo != NULL ) {
551
+ zval_ptr_dtor_str (key);
552
+ ZVAL_STR_COPY (key, existing_propinfo->name );
553
+ return 1 ;
507
554
}
508
555
} else {
509
- if (EXPECTED (Z_TYPE (key) == IS_STRING)) {
556
+ if (!strcmp (unmangled_class, " *" )
557
+ || !strcasecmp (unmangled_class, ZSTR_VAL (ce->name ))) {
558
+ zend_string *unmangled = zend_string_init (unmangled_prop, unmangled_prop_len, 0 );
559
+
560
+ existing_propinfo = zend_hash_find_ptr (&ce->properties_info , unmangled);
561
+ if (existing_propinfo != NULL ) {
562
+ zend_string_release_ex (unmangled, 0 );
563
+ zval_ptr_dtor_str (key);
564
+ ZVAL_STR_COPY (key, existing_propinfo->name );
565
+ return 1 ;
566
+ } else {
567
+ zval_ptr_dtor_str (key);
568
+ ZVAL_STR (key, unmangled);
569
+ return 0 ;
570
+ }
571
+ }
572
+ }
573
+ }
574
+ return 0 ;
575
+ }
576
+
577
+
578
+ static zend_always_inline int process_nested_object_data (UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
579
+ {
580
+ if (var_hash) {
581
+ if ((*var_hash)->max_depth > 0 && (*var_hash)->cur_depth >= (*var_hash)->max_depth ) {
582
+ php_error_docref (NULL , E_WARNING,
583
+ " Maximum depth of " ZEND_LONG_FMT " exceeded. "
584
+ " The depth limit can be changed using the max_depth unserialize() option "
585
+ " or the unserialize_max_depth ini setting" ,
586
+ (*var_hash)->max_depth );
587
+ return 0 ;
588
+ }
589
+ (*var_hash)->cur_depth ++;
590
+ }
591
+
592
+ while (elements-- > 0 ) {
593
+ zval key, *data, d, *old_data;
594
+ zend_property_info *info = NULL ;
595
+
596
+ ZVAL_UNDEF (&key);
597
+
598
+ if (!php_var_unserialize_internal (&key, p, max, NULL , 1 )) {
599
+ zval_ptr_dtor (&key);
600
+ goto failure;
601
+ }
602
+
603
+ data = NULL ;
604
+ ZVAL_UNDEF (&d);
605
+
606
+ if (EXPECTED (Z_TYPE (key) == IS_STRING)) {
510
607
string_key:
511
- if (obj && zend_hash_num_elements (&obj->ce ->properties_info ) > 0 ) {
512
- zend_property_info *existing_propinfo;
513
- zend_string *new_key;
514
- const char *unmangled_class = NULL ;
515
- const char *unmangled_prop;
516
- size_t unmangled_prop_len;
517
- zend_string *unmangled;
518
-
519
- if (UNEXPECTED (zend_unmangle_property_name_ex (Z_STR (key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
520
- zval_ptr_dtor (&key);
521
- goto failure;
522
- }
608
+ if ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL ) {
609
+ if (Z_TYPE_P (old_data) == IS_INDIRECT) {
610
+ declared_property:
611
+ /* This is a property with a declaration */
612
+ old_data = Z_INDIRECT_P (old_data);
613
+ info = zend_get_typed_property_info_for_slot (obj, old_data);
614
+ if (info) {
615
+ if (Z_ISREF_P (old_data)) {
616
+ /* If the value is overwritten, remove old type source from ref. */
617
+ ZEND_REF_DEL_TYPE_SOURCE (Z_REF_P (old_data), info);
618
+ }
523
619
524
- unmangled = zend_string_init (unmangled_prop, unmangled_prop_len, 0 );
525
-
526
- existing_propinfo = zend_hash_find_ptr (&obj->ce ->properties_info , unmangled);
527
- if ((unmangled_class == NULL || !strcmp (unmangled_class, " *" ) || !strcasecmp (unmangled_class, ZSTR_VAL (obj->ce ->name )))
528
- && (existing_propinfo != NULL )
529
- && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) {
530
- if (existing_propinfo->flags & ZEND_ACC_PROTECTED) {
531
- new_key = zend_mangle_property_name (
532
- " *" , 1 , ZSTR_VAL (unmangled), ZSTR_LEN (unmangled), 0 );
533
- zend_string_release_ex (unmangled, 0 );
534
- } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) {
535
- if (unmangled_class != NULL && strcmp (unmangled_class, " *" ) != 0 ) {
536
- new_key = zend_mangle_property_name (
537
- unmangled_class, strlen (unmangled_class),
538
- ZSTR_VAL (unmangled), ZSTR_LEN (unmangled),
539
- 0 );
540
- } else {
541
- new_key = zend_mangle_property_name (
542
- ZSTR_VAL (existing_propinfo->ce ->name ), ZSTR_LEN (existing_propinfo->ce ->name ),
543
- ZSTR_VAL (unmangled), ZSTR_LEN (unmangled),
544
- 0 );
545
- }
546
- zend_string_release_ex (unmangled, 0 );
547
- } else {
548
- ZEND_ASSERT (existing_propinfo->flags & ZEND_ACC_PUBLIC);
549
- new_key = unmangled;
620
+ if ((*var_hash)->ref_props ) {
621
+ /* Remove old entry from ref_props table, if it exists. */
622
+ zend_hash_index_del (
623
+ (*var_hash)->ref_props , (zend_uintptr_t ) old_data);
550
624
}
551
- zval_ptr_dtor_str (&key);
552
- ZVAL_STR (&key, new_key);
625
+ }
626
+ var_push_dtor (var_hash, old_data);
627
+ Z_TRY_DELREF_P (old_data);
628
+ ZVAL_NULL (old_data);
629
+ data = old_data;
630
+ } else {
631
+ int ret = is_property_visibility_changed (obj->ce , &key);
632
+
633
+ if (EXPECTED (!ret)) {
634
+ var_push_dtor (var_hash, old_data);
635
+ data = zend_hash_update (ht, Z_STR (key), &d);
636
+ } else if (ret < 0 ) {
637
+ goto failure;
553
638
} else {
554
- zend_string_release_ex (unmangled, 0 ) ;
639
+ goto second_try ;
555
640
}
556
641
}
642
+ } else {
643
+ int ret = is_property_visibility_changed (obj->ce , &key);
557
644
558
- if ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL ) {
559
- if (Z_TYPE_P (old_data) == IS_INDIRECT) {
560
- /* This is a property with a declaration */
561
- old_data = Z_INDIRECT_P (old_data);
562
- info = zend_get_typed_property_info_for_slot (obj, old_data);
563
- if (info) {
564
- if (Z_ISREF_P (old_data)) {
565
- /* If the value is overwritten, remove old type source from ref. */
566
- ZEND_REF_DEL_TYPE_SOURCE (Z_REF_P (old_data), info);
567
- }
568
-
569
- if ((*var_hash)->ref_props ) {
570
- /* Remove old entry from ref_props table, if it exists. */
571
- zend_hash_index_del (
572
- (*var_hash)->ref_props , (zend_uintptr_t ) old_data);
573
- }
645
+ if (EXPECTED (!ret)) {
646
+ data = zend_hash_add_new (ht, Z_STR (key), &d);
647
+ } else if (ret < 0 ) {
648
+ goto failure;
649
+ } else {
650
+ second_try:
651
+ if ((old_data = zend_hash_find (ht, Z_STR (key))) != NULL ) {
652
+ if (Z_TYPE_P (old_data) == IS_INDIRECT) {
653
+ goto declared_property;
654
+ } else {
655
+ var_push_dtor (var_hash, old_data);
656
+ data = zend_hash_update (ht, Z_STR (key), &d);
574
657
}
575
- var_push_dtor (var_hash, old_data);
576
- Z_TRY_DELREF_P (old_data);
577
- ZVAL_COPY_VALUE (old_data, &d);
578
- data = old_data;
579
658
} else {
580
- var_push_dtor (var_hash, old_data);
581
- data = zend_hash_update_ind (ht, Z_STR (key), &d);
659
+ data = zend_hash_add_new (ht, Z_STR (key), &d);
582
660
}
583
- } else {
584
- data = zend_hash_add_new (ht, Z_STR (key), &d);
585
661
}
586
- } else if (Z_TYPE (key) == IS_LONG) {
587
- /* object properties should include no integers */
588
- convert_to_string (&key);
589
- goto string_key;
590
- } else {
591
- zval_ptr_dtor (&key);
592
- goto failure;
593
662
}
663
+ zval_ptr_dtor_str (&key);
664
+ } else if (Z_TYPE (key) == IS_LONG) {
665
+ /* object properties should include no integers */
666
+ convert_to_string (&key);
667
+ goto string_key;
668
+ } else {
669
+ zval_ptr_dtor (&key);
670
+ goto failure;
594
671
}
595
672
596
673
if (!php_var_unserialize_internal (data, p, max, var_hash, 0 )) {
@@ -599,15 +676,13 @@ string_key:
599
676
* The data is still stored in the property. */
600
677
ZEND_REF_ADD_TYPE_SOURCE (Z_REF_P (data), info);
601
678
}
602
- zval_ptr_dtor (&key);
603
679
goto failure;
604
680
}
605
681
606
682
if (UNEXPECTED (info)) {
607
683
if (!zend_verify_prop_assignable_by_ref (info, data, /* strict */ 1 )) {
608
684
zval_ptr_dtor (data);
609
685
ZVAL_UNDEF (data);
610
- zval_ptr_dtor_nogc (&key);
611
686
goto failure;
612
687
}
613
688
@@ -628,7 +703,6 @@ string_key:
628
703
if (BG (unserialize).level > 1 ) {
629
704
var_push_dtor (var_hash, data);
630
705
}
631
- zval_ptr_dtor_str (&key);
632
706
633
707
if (elements && *(*p-1 ) != ' ;' && *(*p-1 ) != ' }' ) {
634
708
(*p)--;
@@ -707,7 +781,7 @@ static inline int object_common(UNSERIALIZE_PARAMETER, zend_long elements, bool
707
781
array_init_size (&ary, elements);
708
782
/* Avoid reallocation due to packed -> mixed conversion. */
709
783
zend_hash_real_init_mixed (Z_ARRVAL (ary));
710
- if (!process_nested_data (UNSERIALIZE_PASSTHRU, Z_ARRVAL (ary), elements, NULL )) {
784
+ if (!process_nested_array_data (UNSERIALIZE_PASSTHRU, Z_ARRVAL (ary), elements)) {
711
785
ZVAL_DEREF (rval);
712
786
GC_ADD_FLAGS (Z_OBJ_P (rval), IS_OBJ_DESTRUCTOR_CALLED);
713
787
zval_ptr_dtor (&ary);
@@ -735,7 +809,7 @@ static inline int object_common(UNSERIALIZE_PARAMETER, zend_long elements, bool
735
809
}
736
810
737
811
zend_hash_extend (ht, zend_hash_num_elements (ht) + elements, HT_FLAGS (ht) & HASH_FLAG_PACKED);
738
- if (!process_nested_data (UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P (rval))) {
812
+ if (!process_nested_object_data (UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P (rval))) {
739
813
if (has_wakeup) {
740
814
ZVAL_DEREF (rval);
741
815
GC_ADD_FLAGS (Z_OBJ_P (rval), IS_OBJ_DESTRUCTOR_CALLED);
@@ -1025,7 +1099,7 @@ use_double:
1025
1099
* prohibit " r:" references to non-objects, as we only generate them for objects. */
1026
1100
HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
1027
1101
1028
- if (!process_nested_data (UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, NULL )) {
1102
+ if (!process_nested_array_data (UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements)) {
1029
1103
return 0;
1030
1104
}
1031
1105
0 commit comments