@@ -595,132 +595,87 @@ static zend_always_inline bool zend_scope_is_derived_from(
595595 return false;
596596}
597597
598- static zend_always_inline bool zend_has_active_derived_ctor_with_promoted_property (
599- const zend_execute_data * ex , zend_object * obj , const zend_property_info * prop_info )
600- {
601- for (const zend_execute_data * prev = ex -> prev_execute_data ; prev != NULL ; prev = prev -> prev_execute_data ) {
602- if (!(ZEND_CALL_INFO (prev ) & ZEND_CALL_HAS_THIS )
603- || !(prev -> func -> common .fn_flags & ZEND_ACC_CTOR )
604- || Z_OBJ (prev -> This ) != obj ) {
605- continue ;
606- }
607-
608- zend_class_entry * scope = prev -> func -> common .scope ;
609- if (scope == NULL || !zend_scope_is_derived_from (scope , ex -> func -> common .scope )) {
610- continue ;
611- }
612-
613- zend_property_info * scope_prop = (zend_property_info * ) zend_hash_find_ptr (
614- & scope -> properties_info , prop_info -> name );
615- if (scope_prop != NULL
616- && (scope_prop -> flags & (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED ))
617- == (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED )) {
618- return true;
619- }
620- }
621-
622- return false;
623- }
624-
625598static zend_always_inline bool zend_has_active_ctor_with_promoted_property (
626599 const zend_execute_data * ex , zend_object * obj , zend_string * property_name )
627600{
628601 for (const zend_execute_data * frame = ex ; frame != NULL ; frame = frame -> prev_execute_data ) {
629- if (!(ZEND_CALL_INFO (frame ) & ZEND_CALL_HAS_THIS )
630- || !(frame -> func -> common .fn_flags & ZEND_ACC_CTOR )
631- || Z_OBJ (frame -> This ) != obj ) {
602+ if (!(ZEND_CALL_INFO (frame ) & ZEND_CALL_HAS_THIS ) || Z_OBJ (frame -> This ) != obj ) {
603+ return false;
604+ }
605+ if (!(frame -> func -> common .fn_flags & ZEND_ACC_CTOR )) {
632606 continue ;
633607 }
634608
635609 zend_class_entry * scope = frame -> func -> common .scope ;
636- if (scope == NULL ) {
637- continue ;
638- }
610+ ZEND_ASSERT (scope );
639611
640- zend_property_info * scope_prop = (zend_property_info * ) zend_hash_find_ptr (
641- & scope -> properties_info , property_name );
642- if (scope_prop != NULL
643- && (scope_prop -> flags & (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED ))
644- == (ZEND_ACC_READONLY | ZEND_ACC_PROMOTED )) {
645- return true;
646- }
612+ zend_property_info * scope_prop = (zend_property_info * ) zend_hash_find_ptr (& scope -> properties_info , property_name );
613+ ZEND_ASSERT (scope_prop );
614+ return scope_prop -> ce == scope && (scope_prop -> flags & (ZEND_ACC_READONLY |ZEND_ACC_PROMOTED )) == (ZEND_ACC_READONLY |ZEND_ACC_PROMOTED );
647615 }
648616
649617 return false;
650618}
651619
652- static zend_always_inline bool zend_is_promoted_readonly_ctor_init_assign (
653- const zend_execute_data * ex , const zend_property_info * prop_info )
654- {
655- if (ex == NULL
656- || ex -> opline == NULL
657- || !((ex -> opline -> opcode == ZEND_ASSIGN_OBJ || ex -> opline -> opcode == ZEND_ASSIGN_OBJ_REF )
658- && (ex -> opline -> extended_value & ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT ))) {
659- return false;
660- }
661- if (!(ZEND_CALL_INFO (ex ) & ZEND_CALL_HAS_THIS )) {
662- return false;
663- }
664- return zend_has_active_ctor_with_promoted_property (ex , Z_OBJ (ex -> This ), prop_info -> name );
665- }
666-
667- static zend_always_inline zend_object * zend_property_owner_from_slot (
668- const zval * property_val , const zend_property_info * prop_info )
669- {
670- return (zend_object * ) ((char * ) property_val - prop_info -> offset );
671- }
672-
673- typedef enum _zend_readonly_write_kind {
674- ZEND_READONLY_WRITE_FORBIDDEN = 0 , /* Write disallowed, or no special flag update needed */
675- ZEND_READONLY_WRITE_REINITABLE , /* Clone reinit window: clear IS_PROP_REINITABLE after write */
676- ZEND_READONLY_WRITE_CTOR_REASSIGNED , /* CPP ctor reassignment: set IS_PROP_CTOR_REASSIGNED after write */
677- } zend_readonly_write_kind ;
620+ typedef enum _zend_property_write_kind {
621+ ZEND_PROPERTY_WRITE_FORBIDDEN = 0 , /* Write disallowed */
622+ ZEND_PROPERTY_WRITE_OK , /* Write allowed */
623+ ZEND_PROPERTY_WRITE_READONLY_REINITABLE , /* Clone reinit window: clear IS_PROP_REINITABLE after write */
624+ ZEND_PROPERTY_WRITE_READONLY_CTOR_REASSIGNED , /* CPP ctor reassignment: set IS_PROP_CTOR_REASSIGNED after write */
625+ } zend_property_write_kind ;
678626
679- static zend_always_inline zend_readonly_write_kind zend_get_readonly_write_kind (
627+ static zend_always_inline zend_property_write_kind zend_get_readonly_write_kind (
680628 const zval * property_val , const zend_property_info * prop_info )
681629{
682630 if (Z_PROP_FLAG_P (property_val ) & IS_PROP_REINITABLE ) {
683- return ZEND_READONLY_WRITE_REINITABLE ;
631+ return ZEND_PROPERTY_WRITE_READONLY_REINITABLE ;
684632 }
685633 if (Z_PROP_FLAG_P (property_val ) & IS_PROP_CTOR_REASSIGNED ) {
686- return ZEND_READONLY_WRITE_FORBIDDEN ;
634+ return ZEND_PROPERTY_WRITE_FORBIDDEN ;
687635 }
688636 zend_execute_data * ex = EG (current_execute_data );
689- if (ex == NULL
690- || !(ZEND_CALL_INFO (ex ) & ZEND_CALL_HAS_THIS )
691- || !zend_has_active_ctor_with_promoted_property (ex , Z_OBJ (ex -> This ), prop_info -> name )
692- || zend_property_owner_from_slot (property_val , prop_info ) != Z_OBJ (ex -> This )
693- || (ex -> opline != NULL
694- && (ex -> opline -> opcode == ZEND_ASSIGN_OBJ || ex -> opline -> opcode == ZEND_ASSIGN_OBJ_REF )
695- && (ex -> opline -> extended_value & ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT ))) {
696- return ZEND_READONLY_WRITE_FORBIDDEN ;
637+ if (ex == NULL || !(ZEND_CALL_INFO (ex ) & ZEND_CALL_HAS_THIS )) {
638+ return ZEND_PROPERTY_WRITE_FORBIDDEN ;
697639 }
698- return ZEND_READONLY_WRITE_CTOR_REASSIGNED ;
640+ zend_object * obj = zend_get_object_from_slot (property_val , prop_info );
641+ if (!zend_has_active_ctor_with_promoted_property (ex , obj , prop_info -> name )
642+ || (ex -> opline
643+ && (ex -> opline -> opcode == ZEND_ASSIGN_OBJ || ex -> opline -> opcode == ZEND_ASSIGN_OBJ_REF )
644+ && (ex -> opline -> extended_value & ZEND_ASSIGN_OBJ_PROMOTED_READONLY_INIT ))) {
645+ return ZEND_PROPERTY_WRITE_FORBIDDEN ;
646+ }
647+ return ZEND_PROPERTY_WRITE_READONLY_CTOR_REASSIGNED ;
699648}
700649
701- /* Check if a foreign constructor is attempting a CPP initial assignment on an
702- * already-initialized property owned by a different class (e.g., child has CPP
703- * for $x, parent's CPP also tries to set $x on the child's object). */
704- static zend_always_inline bool zend_is_foreign_cpp_overwrite (
705- const zval * property_val , const zend_property_info * prop_info )
650+ static zend_always_inline zend_property_write_kind zend_verify_readonly_and_avis (
651+ zval * property_val , const zend_property_info * info , bool indirect )
706652{
707- if (Z_PROP_FLAG_P (property_val ) & IS_PROP_UNINIT ) {
708- return false;
709- }
710- zend_execute_data * ex = EG (current_execute_data );
711- if (!ex
712- || !(ex -> func -> common .fn_flags & ZEND_ACC_CTOR )
713- || !(ZEND_CALL_INFO (ex ) & ZEND_CALL_HAS_THIS )) {
714- return false;
715- }
716- if ((prop_info -> flags & ZEND_ACC_PROMOTED ) && ex -> func -> common .scope != prop_info -> ce ) {
717- return true;
653+ if (UNEXPECTED (info -> flags & (ZEND_ACC_READONLY |ZEND_ACC_PPP_SET_MASK ))) {
654+ zend_property_write_kind prop_write_kind = ZEND_PROPERTY_WRITE_OK ;
655+ if ((info -> flags & ZEND_ACC_READONLY ) && !Z_ISUNDEF_P (property_val )) {
656+ prop_write_kind = zend_get_readonly_write_kind (property_val , info );
657+ if (prop_write_kind == ZEND_PROPERTY_WRITE_FORBIDDEN ) {
658+ zend_readonly_property_modification_error (info );
659+ return ZEND_PROPERTY_WRITE_FORBIDDEN ;
660+ }
661+ }
662+ if ((info -> flags & ZEND_ACC_PPP_SET_MASK ) && !zend_asymmetric_property_has_set_access (info )) {
663+ const char * operation = indirect ? "indirectly modify" : "modify" ;
664+ zend_asymmetric_visibility_property_modification_error (info , operation );
665+ return ZEND_PROPERTY_WRITE_FORBIDDEN ;
666+ }
667+ return prop_write_kind ;
718668 }
719- if (!(prop_info -> flags & ZEND_ACC_PROMOTED )
720- && zend_has_active_derived_ctor_with_promoted_property (ex , Z_OBJ (ex -> This ), prop_info )) {
721- return true;
669+ return ZEND_PROPERTY_WRITE_OK ;
670+ }
671+
672+ static zend_always_inline void zend_property_write_commit (zval * property_val , zend_property_write_kind kind )
673+ {
674+ if (kind == ZEND_PROPERTY_WRITE_READONLY_REINITABLE ) {
675+ Z_PROP_FLAG_P (property_val ) &= ~IS_PROP_REINITABLE ;
676+ } else if (kind == ZEND_PROPERTY_WRITE_READONLY_CTOR_REASSIGNED ) {
677+ Z_PROP_FLAG_P (property_val ) |= IS_PROP_CTOR_REASSIGNED ;
722678 }
723- return false;
724679}
725680
726681ZEND_API bool zend_verify_class_constant_type (const zend_class_constant * c , const zend_string * name , zval * constant );
0 commit comments