@@ -460,130 +460,6 @@ static uint32_t spl_array_set_refcount(bool is_child, HashTable *ht, uint32_t re
460
460
return old_refcount ;
461
461
} /* }}} */
462
462
463
- /* For reasons ArrayObject must not go through the overloaded __set()/__get()/etc.
464
- * magic methods, so to emit a warning for dynamic props (or Error on classes
465
- * that do not support them, such as readonly classes) or an error for incompatible
466
- * typed properties, we need to reimplement the logic of zend_std_write_property()
467
- * somewhat. Thanks SPL. */
468
- static zval * zend_ignore_set_magic_method_write_property (
469
- HashTable * derived_properties_table ,
470
- zend_object * zobj ,
471
- zend_string * property_name ,
472
- zval * value
473
- ) {
474
- ZEND_ASSERT (!Z_ISREF_P (value ));
475
-
476
- zend_class_entry * ce = zobj -> ce ;
477
- zval * zv ;
478
- if (UNEXPECTED (zend_hash_num_elements (& ce -> properties_info ) == 0 )
479
- || UNEXPECTED ((zv = zend_hash_find (& ce -> properties_info , property_name )) == NULL )) {
480
- /* Dynamic prop handling */
481
- dynamic_prop :
482
- /* TODO Modifying private/protected props?
483
- if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0') && ZSTR_LEN(member) != 0) {
484
- zend_bad_property_name();
485
- return NULL;
486
- }
487
- */
488
- // Dynamic props are not allowed on this class
489
- if (ce -> ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES ) {
490
- zend_throw_error (NULL , "Cannot create dynamic property %s::$%s" , ZSTR_VAL (ce -> name ), ZSTR_VAL (property_name ));
491
- return NULL ;
492
- }
493
- if (UNEXPECTED (!(ce -> ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES ))) {
494
- GC_ADDREF (zobj );
495
- zend_error (E_DEPRECATED , "Creation of dynamic property %s::$%s is deprecated" , ZSTR_VAL (ce -> name ), ZSTR_VAL (property_name ));
496
- if (UNEXPECTED (GC_DELREF (zobj ) == 0 )) {
497
- zend_objects_store_del (zobj );
498
- if (!EG (exception )) {
499
- /* We cannot continue execution and have to throw an exception */
500
- zend_throw_error (NULL , "Cannot create dynamic property %s::$%s" , ZSTR_VAL (ce -> name ), ZSTR_VAL (property_name ));
501
- }
502
- return NULL ;
503
- }
504
- }
505
- /* Create/Update dynamic prop */
506
- zend_hash_update_ind (derived_properties_table , property_name , value );
507
- return value ;
508
- }
509
-
510
- const zend_property_info * property_info = (zend_property_info * )Z_PTR_P (zv );
511
- uint32_t prop_flags = property_info -> flags ;
512
-
513
- if (prop_flags & (ZEND_ACC_CHANGED |ZEND_ACC_PROTECTED |ZEND_ACC_PRIVATE )) {
514
- zend_throw_error (NULL , "Cannot access %s property %s::$%s" , zend_visibility_string (prop_flags ), ZSTR_VAL (ce -> name ), ZSTR_VAL (property_name ));
515
- return NULL ;
516
- }
517
- if (UNEXPECTED (prop_flags & ZEND_ACC_STATIC )) {
518
- zend_error (E_NOTICE , "Accessing static property %s::$%s as non static" , ZSTR_VAL (ce -> name ), ZSTR_VAL (property_name ));
519
- /* Handle like dynamic prop */
520
- goto dynamic_prop ;
521
- }
522
-
523
- uintptr_t property_offset = property_info -> offset ;
524
- zval * variable_ptr = OBJ_PROP (zobj , property_offset );
525
-
526
- // Property is already set, check readonly violation
527
- if (Z_TYPE_P (variable_ptr ) != IS_UNDEF ) {
528
- if (UNEXPECTED ((prop_flags & ZEND_ACC_READONLY ) && !(Z_PROP_FLAG_P (variable_ptr ) & IS_PROP_REINITABLE ))) {
529
- Z_TRY_DELREF_P (value );
530
- zend_readonly_property_modification_error (property_info );
531
- return NULL ;
532
- }
533
- }
534
-
535
- /* Remove fact that property can be reinitialized */
536
- Z_PROP_FLAG_P (variable_ptr ) &= ~IS_PROP_REINITABLE ;
537
- Z_TRY_ADDREF_P (value );
538
- /* Check value is of valid type if property has type */
539
- if (UNEXPECTED (ZEND_TYPE_IS_SET (property_info -> type ))) {
540
- zval tmp ;
541
- ZVAL_COPY_VALUE (& tmp , value );
542
- // Increase refcount to prevent object from being released in __toString()
543
- GC_ADDREF (zobj );
544
- /* Engine never uses strict types */
545
- bool type_matched = zend_verify_property_type (property_info , & tmp , /* strict_types */ false);
546
- if (UNEXPECTED (GC_DELREF (zobj ) == 0 )) {
547
- zend_object_released_while_assigning_to_property_error (property_info );
548
- zend_objects_store_del (zobj );
549
- zval_ptr_dtor (& tmp );
550
- variable_ptr = & EG (error_zval );
551
- return NULL ;
552
- }
553
- if (UNEXPECTED (!type_matched )) {
554
- zval_ptr_dtor (value );
555
- return NULL ;
556
- }
557
- value = & tmp ;
558
- Z_PROP_FLAG_P (variable_ptr ) = 0 ;
559
- }
560
-
561
- zend_refcounted * garbage = NULL ;
562
- /* Engine never uses strict types */
563
- variable_ptr = zend_assign_to_variable_ex (variable_ptr , value , IS_TMP_VAR , /* strict_types */ false, & garbage );
564
- if (garbage ) {
565
- if (GC_DELREF (garbage ) == 0 ) {
566
- zend_execute_data * execute_data = EG (current_execute_data );
567
- // Assign to result variable before calling the destructor as it may release the object
568
- if (execute_data
569
- && EX (func )
570
- && ZEND_USER_CODE (EX (func )-> common .type )
571
- && EX (opline )
572
- && EX (opline )-> opcode == ZEND_ASSIGN_OBJ
573
- && EX (opline )-> result_type
574
- ) {
575
- ZVAL_COPY_DEREF (EX_VAR (EX (opline )-> result .var ), variable_ptr );
576
- variable_ptr = NULL ;
577
- }
578
- rc_dtor_func (garbage );
579
- } else {
580
- gc_check_possible_root_no_ref (garbage );
581
- }
582
- }
583
- //ZVAL_COPY_VALUE(variable_ptr, value);
584
- return variable_ptr ;
585
- }
586
-
587
463
static void spl_array_write_dimension_ex (int check_inherited , zend_object * object , zval * offset , zval * value ) /* {{{ */
588
464
{
589
465
spl_array_object * intern = spl_array_from_obj (object );
@@ -620,11 +496,8 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
620
496
return ;
621
497
}
622
498
623
- Z_TRY_ADDREF_P (value );
624
-
625
499
if (get_hash_key (& key , intern , offset ) == FAILURE ) {
626
500
zend_illegal_container_offset (object -> ce -> name , offset , BP_VAR_W );
627
- zval_ptr_dtor (value );
628
501
return ;
629
502
}
630
503
@@ -637,14 +510,27 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
637
510
/* For reasons ArrayObject must not go through the overloaded __set()/__get()/etc.
638
511
* magic methods, so to emit a warning for dynamic props (or Error on classes
639
512
* that do not support them, such as readonly classes) or an error for incompatible
640
- * typed properties, we need to reimplement the logic of zend_std_write_property()
641
- * somewhat. Thanks SPL. */
642
- zend_ignore_set_magic_method_write_property (ht , obj , key .key , value );
513
+ * typed properties, we set a property guard so that when calling the write_property
514
+ * handler it does not call the magic __set() method. Thanks SPL. */
515
+ if (obj -> ce -> ce_flags & ZEND_ACC_USE_GUARDS ) {
516
+ uint32_t * guard = zend_get_property_guard (obj , key .key );
517
+ uint32_t backup = * guard ;
518
+ (* guard ) |= ZEND_GUARD_PROPERTY_SET ;
519
+ obj -> handlers -> write_property (obj , key .key , value , /* cache_slot */ NULL );
520
+ * guard = backup ;
521
+ } else {
522
+ /* No overload method is defined on the object */
523
+ obj -> handlers -> write_property (obj , key .key , value , /* cache_slot */ NULL );
524
+ }
643
525
} else {
526
+ /* Increase refcount for value before adding to the Hashtable */
527
+ Z_TRY_ADDREF_P (value );
644
528
zend_hash_update_ind (ht , key .key , value );
645
529
}
646
530
spl_hash_key_release (& key );
647
531
} else {
532
+ /* Increase refcount for value before adding to the Hashtable */
533
+ Z_TRY_ADDREF_P (value );
648
534
ZEND_ASSERT (!spl_array_is_object (intern ));
649
535
zend_hash_index_update (ht , key .h , value );
650
536
}
0 commit comments