Skip to content

Commit 3db38fb

Browse files
committed
Address some code review comments
1 parent 1f0f38c commit 3db38fb

16 files changed

+760
-1778
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Test that clone initializer list is displayed properly in assert()
3+
--INI--
4+
zend.assertions = 1
5+
assert.warning = 0
6+
assert.exception = 1
7+
--FILE--
8+
<?php
9+
10+
try {
11+
assert(clone new stdClass() === null);
12+
} catch (AssertionError $e) {
13+
echo $e->getMessage() . "\n";
14+
}
15+
16+
try {
17+
assert(clone new stdClass() with {} === null);
18+
} catch (AssertionError $e) {
19+
echo $e->getMessage() . "\n";
20+
}
21+
22+
try {
23+
assert(clone new stdClass() with {foo: 1, bar: "abc"} === null);
24+
} catch (AssertionError $e) {
25+
echo $e->getMessage() . "\n";
26+
}
27+
28+
?>
29+
--EXPECT--
30+
assert(clone new stdClass() === null)
31+
assert(clone new stdClass() with {} === null)
32+
assert(clone new stdClass() with {foo: 1, bar: 'abc'} === null)

Zend/zend_API.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4191,6 +4191,10 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
41914191

41924192
if (ZEND_TYPE_IS_SET(type)) {
41934193
ce->ce_flags |= ZEND_ACC_HAS_TYPE_HINTS;
4194+
4195+
if (access_type & ZEND_ACC_READONLY) {
4196+
ce->ce_flags |= ZEND_ACC_HAS_READONLY_PROPS;
4197+
}
41944198
}
41954199

41964200
if (ce->type == ZEND_INTERNAL_CLASS) {

Zend/zend_ast.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,10 +1833,16 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
18331833
zend_ast_export_list(str, (zend_ast_list*)ast, 0, 0, indent);
18341834
break;
18351835
case ZEND_AST_PROPERTY_INITIALIZER_LIST:
1836-
smart_str_appends(str, " {");
1837-
zend_ast_export_list(str, (zend_ast_list*)ast, 0, 0, indent);
1838-
smart_str_appends(str, " }");
1836+
smart_str_appends(str, "{");
1837+
zend_ast_export_list(str, (zend_ast_list*)ast, 1, 0, indent);
1838+
smart_str_appends(str, "}");
1839+
break;
1840+
case ZEND_AST_INITIALIZER_EXPR: {
1841+
zend_ast_export_name(str, ast->child[0], 0, indent);
1842+
smart_str_appends(str, ": ");
1843+
zend_ast_export_ex(str, ast->child[1], priority, indent);
18391844
break;
1845+
}
18401846
case ZEND_AST_CLOSURE_USES:
18411847
smart_str_appends(str, " use(");
18421848
zend_ast_export_var_list(str, (zend_ast_list*)ast, indent);
@@ -1963,8 +1969,6 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
19631969
}
19641970
smart_str_appendc(str, '`');
19651971
break;
1966-
case ZEND_AST_CLONE:
1967-
PREFIX_OP("clone ", 270, 271);
19681972
case ZEND_AST_EXIT:
19691973
if (ast->child[0]) {
19701974
FUNC_OP("exit");
@@ -2160,6 +2164,16 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
21602164
smart_str_appendc(str, ')');
21612165
}
21622166
break;
2167+
case ZEND_AST_CLONE:
2168+
if (ast->child[1]) {
2169+
smart_str_appends(str, "clone ");
2170+
zend_ast_export_ex(str, ast->child[0], priority, indent);
2171+
smart_str_appends(str, " with ");
2172+
zend_ast_export_ex(str, ast->child[1], priority, indent);
2173+
} else {
2174+
PREFIX_OP("clone ", 270, 271);
2175+
}
2176+
break;
21632177
case ZEND_AST_INSTANCEOF:
21642178
zend_ast_export_ex(str, ast->child[0], 0, indent);
21652179
smart_str_appends(str, " instanceof ");

Zend/zend_compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4836,7 +4836,7 @@ static void zend_compile_clone(znode *result, zend_ast *ast) /* {{{ */
48364836
znode property_name_node;
48374837
property_name_node.op_type = IS_CONST;
48384838
ZVAL_STR_COPY(&property_name_node.u.constant, property_name);
4839-
opline = zend_emit_op(result, ZEND_INIT_OBJ, &property_object_node, &property_name_node);
4839+
opline = zend_emit_op(result, ZEND_CLONE_INIT_PROP, &property_object_node, &property_name_node);
48404840
opline->result.var = get_temporary_variable();
48414841
opline->extended_value = zend_alloc_cache_slots(3);
48424842

Zend/zend_compile.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ typedef struct _zend_oparray_context {
240240
/* or IS_CONSTANT_VISITED_MARK | | | */
241241
#define ZEND_CLASS_CONST_IS_CASE (1 << 6) /* | | | X */
242242
/* | | | */
243-
/* Class Flags (unused: 21,30,31) | | | */
243+
/* Class Flags (unused: 30,31) | | | */
244244
/* =========== | | | */
245245
/* | | | */
246246
/* Special class types | | | */
@@ -288,6 +288,9 @@ typedef struct _zend_oparray_context {
288288
/* Class is linked apart from variance obligations. | | | */
289289
#define ZEND_ACC_NEARLY_LINKED (1 << 20) /* X | | | */
290290
/* | | | */
291+
/* Class has readonly props | | | */
292+
#define ZEND_ACC_HAS_READONLY_PROPS (1 << 21) /* X | | | */
293+
/* | | | */
291294
/* stored in opcache (may be partially) | | | */
292295
#define ZEND_ACC_CACHED (1 << 22) /* X | | | */
293296
/* | | | */

Zend/zend_enum.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case
4646
zval *prop = OBJ_PROP_NUM(zobj, 1);
4747

4848
ZVAL_COPY(prop, backing_value_zv);
49+
/* ZVAL_COPY does not set Z_PROP_FLAG, this needs to be cleared to avoid leaving IS_PROP_REINITABLE set */
4950
Z_PROP_FLAG_P(prop) = 0;
5051
}
5152

Zend/zend_execute.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ ZEND_API int ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call);
454454
} while (0)
455455

456456
#define ZEND_CLASS_HAS_TYPE_HINTS(ce) ((ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) == ZEND_ACC_HAS_TYPE_HINTS)
457+
#define ZEND_CLASS_HAS_READONLY_PROPS(ce) ((ce->ce_flags & ZEND_ACC_HAS_READONLY_PROPS) == ZEND_ACC_HAS_READONLY_PROPS)
457458

458459
ZEND_API bool zend_verify_property_type(zend_property_info *info, zval *property, bool strict);
459460
ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *property);

Zend/zend_inheritance.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1628,7 +1628,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
16281628
ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
16291629
}
16301630
}
1631-
ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_USE_GUARDS | ZEND_ACC_NOT_SERIALIZABLE | ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES);
1631+
ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_READONLY_PROPS | ZEND_ACC_USE_GUARDS | ZEND_ACC_NOT_SERIALIZABLE | ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES);
16321632
}
16331633
/* }}} */
16341634

Zend/zend_object_handlers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
816816
if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
817817
if (UNEXPECTED((Z_PROP_FLAG_P(variable_ptr) & IS_PROP_REINITABLE)) ||
818818
(UNEXPECTED(EG(current_execute_data) && EG(current_execute_data)->opline &&
819-
EG(current_execute_data)->opline->opcode == ZEND_INIT_OBJ))
819+
EG(current_execute_data)->opline->opcode == ZEND_CLONE_INIT_PROP))
820820
) {
821821
Z_PROP_FLAG_P(variable_ptr) &= ~IS_PROP_REINITABLE;
822822
} else {

Zend/zend_objects.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,8 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object,
266266
GC_ADDREF(new_object);
267267
zend_call_known_instance_method_with_0_params(new_object->ce->clone, new_object, NULL);
268268

269-
for (uint32_t i = 0; i < new_object->ce->default_properties_count; i++) {
270-
zend_property_info *prop_info = new_object->ce->properties_info_table[i];
271-
if (prop_info && (prop_info->flags & ZEND_ACC_READONLY)) {
269+
if (ZEND_CLASS_HAS_READONLY_PROPS(new_object->ce)) {
270+
for (uint32_t i = 0; i < new_object->ce->default_properties_count; i++) {
272271
zval *prop = OBJ_PROP_NUM(new_object, i);
273272
Z_PROP_FLAG_P(prop) &= ~IS_PROP_REINITABLE;
274273
}

Zend/zend_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,7 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
14381438
* the Z_EXTRA space when copying property default values etc. We define separate
14391439
* macros for this purpose, so this workaround is easier to remove in the future. */
14401440
#define IS_PROP_UNINIT 1
1441-
#define IS_PROP_REINITABLE 2
1441+
#define IS_PROP_REINITABLE 2 /* It has impact only on readonly properties */
14421442
#define Z_PROP_FLAG_P(z) Z_EXTRA_P(z)
14431443
#define ZVAL_COPY_VALUE_PROP(z, v) \
14441444
do { *(z) = *(v); } while (0)

Zend/zend_vm_def.h

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9397,7 +9397,7 @@ ZEND_VM_HANDLER(202, ZEND_CALLABLE_CONVERT, UNUSED, UNUSED)
93979397
ZEND_VM_NEXT_OPCODE();
93989398
}
93999399

9400-
ZEND_VM_HANDLER(203, ZEND_INIT_OBJ, VAR|UNUSED|THIS|CV, CONST, CACHE_SLOT, SPEC(OP_DATA=CONST|TMP|VAR|CV))
9400+
ZEND_VM_HANDLER(203, ZEND_CLONE_INIT_PROP, VAR, CONST, CACHE_SLOT, SPEC(OP_DATA=CONST|TMP|VAR|CV))
94019401
{
94029402
USE_OPLINE
94039403
zval *object, *value, tmp;
@@ -9411,14 +9411,14 @@ ZEND_VM_HANDLER(203, ZEND_INIT_OBJ, VAR|UNUSED|THIS|CV, CONST, CACHE_SLOT, SPEC(
94119411
if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
94129412
if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) {
94139413
object = Z_REFVAL_P(object);
9414-
ZEND_VM_C_GOTO(init_object);
9414+
ZEND_VM_C_GOTO(init_prop);
94159415
}
94169416
zend_throw_non_object_error(object, GET_OP2_ZVAL_PTR(BP_VAR_R) OPLINE_CC EXECUTE_DATA_CC);
94179417
value = &EG(uninitialized_zval);
9418-
ZEND_VM_C_GOTO(free_and_exit_init_obj);
9418+
ZEND_VM_C_GOTO(free_and_exit_init_prop);
94199419
}
94209420

9421-
ZEND_VM_C_LABEL(init_object):
9421+
ZEND_VM_C_LABEL(init_prop):
94229422
zobj = Z_OBJ_P(object);
94239423
void **cache_slot = CACHE_ADDR(opline->extended_value);
94249424
if (EXPECTED(zobj->ce == CACHED_PTR(opline->extended_value))) {
@@ -9439,14 +9439,14 @@ ZEND_VM_C_LABEL(init_object):
94399439
if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
94409440
Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE;
94419441
}
9442-
ZEND_VM_C_GOTO(free_and_exit_init_obj);
9442+
ZEND_VM_C_GOTO(free_and_exit_init_prop);
94439443
} else {
9444-
ZEND_VM_C_LABEL(fast_init_obj):
9445-
value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
9444+
ZEND_VM_C_LABEL(fast_init_prop):
9445+
zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
94469446
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
9447-
ZVAL_COPY(EX_VAR(opline->result.var), value);
9447+
ZVAL_COPY(EX_VAR(opline->result.var), object);
94489448
}
9449-
ZEND_VM_C_GOTO(exit_init_obj);
9449+
ZEND_VM_C_GOTO(exit_init_prop);
94509450
}
94519451
}
94529452
} else {
@@ -9460,7 +9460,7 @@ ZEND_VM_C_LABEL(fast_init_obj):
94609460
}
94619461
property_val = zend_hash_find_known_hash(zobj->properties, name);
94629462
if (property_val) {
9463-
ZEND_VM_C_GOTO(fast_init_obj);
9463+
ZEND_VM_C_GOTO(fast_init_prop);
94649464
}
94659465
}
94669466

@@ -9494,9 +9494,9 @@ ZEND_VM_C_LABEL(fast_init_obj):
94949494
}
94959495
zend_hash_add_new(zobj->properties, name, value);
94969496
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
9497-
ZVAL_COPY(EX_VAR(opline->result.var), value);
9497+
ZVAL_COPY(EX_VAR(opline->result.var), object);
94989498
}
9499-
ZEND_VM_C_GOTO(exit_init_obj);
9499+
ZEND_VM_C_GOTO(free_and_exit_init_prop);
95009500
}
95019501
}
95029502
}
@@ -9509,15 +9509,15 @@ ZEND_VM_C_LABEL(fast_init_obj):
95099509

95109510
value = zobj->handlers->write_property(zobj, name, value, cache_slot);
95119511

9512-
ZEND_VM_C_LABEL(free_and_exit_init_obj):
9512+
ZEND_VM_C_LABEL(free_and_exit_init_prop):
95139513
if (EXPECTED(RETURN_VALUE_USED(opline))) {
95149514
ZVAL_COPY_DEREF(EX_VAR(opline->result.var), object);
95159515
}
95169516
FREE_OP_DATA();
9517-
ZEND_VM_C_LABEL(exit_init_obj):
9517+
ZEND_VM_C_LABEL(exit_init_prop):
95189518
FREE_OP2();
95199519
FREE_OP1();
9520-
/* init_obj has two opcodes! */
9520+
/* ZEND_CLONE_INIT_PROP has two opcodes! */
95219521
ZEND_VM_NEXT_OPCODE_EX(1, 2);
95229522
}
95239523

0 commit comments

Comments
 (0)