Skip to content

Allow FETCH_OBJ_W and FETCH_STATIC_PROP_W to return INDIRECT/UNDEF zval for uninitialized typed properties #11048

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -3436,6 +3436,9 @@ static zend_always_inline int _zend_update_type_info(
tmp |= zend_fetch_prop_type(script, prop_info, &ce);
if (opline->result_type == IS_VAR) {
tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) {
tmp |= MAY_BE_UNDEF;
}
} else if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || !(t1 & MAY_BE_RC1)) {
zend_class_entry *ce = NULL;

Expand Down Expand Up @@ -3473,6 +3476,9 @@ static zend_always_inline int _zend_update_type_info(
zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce);
if (opline->result_type == IS_VAR) {
tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) {
tmp |= MAY_BE_UNDEF;
}
} else {
if (!result_may_be_separated(ssa, ssa_op)) {
tmp &= ~MAY_BE_RC1;
Expand Down
7 changes: 2 additions & 5 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -3087,7 +3087,7 @@ static zend_never_inline bool zend_handle_fetch_obj_flags(
return 1;
}

static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type, uint32_t flags, bool init_undef OPLINE_DC EXECUTE_DATA_DC)
static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type, uint32_t flags OPLINE_DC EXECUTE_DATA_DC)
{
zval *ptr;
zend_object *zobj;
Expand Down Expand Up @@ -3203,9 +3203,6 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
}
}
}
if (init_undef && UNEXPECTED(Z_TYPE_P(ptr) == IS_UNDEF)) {
ZVAL_NULL(ptr);
}

end:
if (prop_op_type != IS_CONST) {
Expand All @@ -3219,7 +3216,7 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container
void **cache_addr = (prop_op_type == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_RETURNS_FUNCTION) : NULL;

zend_fetch_property_address(variable_ptr, container, container_op_type, prop_ptr, prop_op_type,
cache_addr, BP_VAR_W, 0, 0 OPLINE_CC EXECUTE_DATA_CC);
cache_addr, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);

if (EXPECTED(Z_TYPE_P(variable_ptr) == IS_INDIRECT)) {
variable_ptr = Z_INDIRECT_P(variable_ptr);
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,8 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam
} else if (prop_info && UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
/* Readonly property, delegate to read_property + write_property. */
retval = NULL;
} else if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
ZVAL_NULL(retval);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this change?

Copy link
Member Author

@dstogov dstogov Apr 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ZVAL_NULL() was moved into zend_fetch_property_address() by typed-properties patch.
Without it uninitialized not-typed properties are not converted to NULL.
Zend/tests/type_declarations/typed_properties_098.phpt was broken.

}
} else {
/* we do have getter - fail and let it try again with usual get/set */
Expand Down
6 changes: 3 additions & 3 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -2157,7 +2157,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, FETCH
zend_fetch_property_address(
result, container, OP1_TYPE, property, OP2_TYPE,
((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL),
BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC);
BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS OPLINE_CC EXECUTE_DATA_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR) {
FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var);
Expand All @@ -2174,7 +2174,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACH
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
result = EX_VAR(opline->result.var);
zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC);
zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR) {
FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var);
Expand Down Expand Up @@ -2321,7 +2321,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, C
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET);
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
result = EX_VAR(opline->result.var);
zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC);
zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR) {
FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var);
Expand Down
Loading