Skip to content

Commit 2d6b28a

Browse files
committed
Use attribute validator for assigning flags
1 parent ba97d86 commit 2d6b28a

File tree

4 files changed

+80
-93
lines changed

4 files changed

+80
-93
lines changed

Zend/zend_attributes.c

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_ent
7070
}
7171

7272
static void validate_allow_dynamic_properties(
73-
zend_attribute *attr, uint32_t target, zend_class_entry *scope)
73+
zend_attribute *attr, uint32_t target_type, zend_class_entry *scope, void *target, uint32_t offset)
7474
{
7575
if (scope->ce_flags & ZEND_ACC_TRAIT) {
7676
zend_error_noreturn(E_ERROR, "Cannot apply #[\\AllowDynamicProperties] to trait %s",
@@ -96,7 +96,7 @@ static void validate_allow_dynamic_properties(
9696
}
9797

9898
static void validate_attribute(
99-
zend_attribute *attr, uint32_t target, zend_class_entry *scope)
99+
zend_attribute *attr, uint32_t target_type, zend_class_entry *scope, void *target, uint32_t offset)
100100
{
101101
const char *msg = NULL;
102102
if (scope->ce_flags & ZEND_ACC_TRAIT) {
@@ -113,6 +113,51 @@ static void validate_attribute(
113113
}
114114
}
115115

116+
static void validate_override(
117+
zend_attribute *attr, uint32_t target_type, zend_class_entry *scope, void *target, uint32_t offset)
118+
{
119+
if (target_type & ZEND_ATTRIBUTE_TARGET_METHOD) {
120+
zend_op_array *op_array = target;
121+
op_array->fn_flags |= ZEND_ACC_OVERRIDE;
122+
} else {
123+
ZEND_ASSERT(target_type & ZEND_ATTRIBUTE_TARGET_PROPERTY);
124+
zend_property_info *prop_info = target;
125+
prop_info->flags |= ZEND_ACC_OVERRIDE;
126+
}
127+
}
128+
129+
static void validate_deprecated(
130+
zend_attribute *attr, uint32_t target_type, zend_class_entry *scope, void *target, uint32_t offset)
131+
{
132+
if (target_type & (ZEND_ATTRIBUTE_TARGET_FUNCTION|ZEND_ATTRIBUTE_TARGET_METHOD)) {
133+
zend_op_array *op_array = target;
134+
op_array->fn_flags |= ZEND_ACC_DEPRECATED;
135+
} else if (target_type & (ZEND_ATTRIBUTE_TARGET_CLASS_CONST)) {
136+
zend_class_constant *c = target;
137+
ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
138+
/* For deprecated constants, we need to flag the zval for recursion
139+
* detection. Make sure the zval is separated out of shm. */
140+
scope->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
141+
scope->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
142+
} else {
143+
ZEND_ASSERT(target_type & ZEND_ATTRIBUTE_TARGET_CONST);
144+
zend_constant *c = target;
145+
ZEND_CONSTANT_SET_FLAGS(
146+
c,
147+
ZEND_CONSTANT_FLAGS(c) | CONST_DEPRECATED,
148+
ZEND_CONSTANT_MODULE_NUMBER(c)
149+
);
150+
}
151+
}
152+
153+
static void validate_no_discard(
154+
zend_attribute *attr, uint32_t target_type, zend_class_entry *scope, void *target, uint32_t offset)
155+
{
156+
ZEND_ASSERT(target_type & (ZEND_ATTRIBUTE_TARGET_FUNCTION|ZEND_ATTRIBUTE_TARGET_METHOD));
157+
zend_op_array *op_array = target;
158+
op_array->fn_flags |= ZEND_ACC_NODISCARD;
159+
}
160+
116161
ZEND_METHOD(Attribute, __construct)
117162
{
118163
zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
@@ -560,13 +605,16 @@ void zend_register_attribute_ce(void)
560605
zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value;
561606

562607
zend_ce_override = register_class_Override();
563-
zend_mark_internal_attribute(zend_ce_override);
608+
attr = zend_mark_internal_attribute(zend_ce_override);
609+
attr->validator = validate_override;
564610

565611
zend_ce_deprecated = register_class_Deprecated();
566612
attr = zend_mark_internal_attribute(zend_ce_deprecated);
613+
attr->validator = validate_deprecated;
567614

568615
zend_ce_nodiscard = register_class_NoDiscard();
569616
attr = zend_mark_internal_attribute(zend_ce_nodiscard);
617+
attr->validator = validate_no_discard;
570618
}
571619

572620
void zend_attributes_shutdown(void)

Zend/zend_attributes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ typedef struct _zend_attribute {
7070
typedef struct _zend_internal_attribute {
7171
zend_class_entry *ce;
7272
uint32_t flags;
73-
void (*validator)(zend_attribute *attr, uint32_t target, zend_class_entry *scope);
73+
/* Parameter offsets start at 1, everything else uses 0. */
74+
void (*validator)(zend_attribute *attr, uint32_t target_type, zend_class_entry *scope, void *target, uint32_t offset);
7475
} zend_internal_attribute;
7576

7677
ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname);

Zend/zend_compile.c

Lines changed: 21 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -7468,7 +7468,7 @@ static bool zend_is_valid_default_value(zend_type type, zval *value)
74687468
}
74697469

74707470
static void zend_compile_attributes(
7471-
HashTable **attributes, zend_ast *ast, uint32_t offset, uint32_t target, uint32_t promoted
7471+
HashTable **attributes, zend_ast *ast, uint32_t offset, uint32_t target_type, uint32_t promoted, void *target
74727472
) /* {{{ */ {
74737473
zend_attribute *attr;
74747474
zend_internal_attribute *config;
@@ -7502,7 +7502,7 @@ static void zend_compile_attributes(
75027502
zend_string_release(lcname);
75037503

75047504
/* Exclude internal attributes that do not match on promoted properties. */
7505-
if (config && !(target & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL))) {
7505+
if (config && !(target_type & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL))) {
75067506
if (promoted & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL)) {
75077507
zend_string_release(name);
75087508
continue;
@@ -7560,8 +7560,8 @@ static void zend_compile_attributes(
75607560
continue;
75617561
}
75627562

7563-
if (!(target & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL))) {
7564-
zend_string *location = zend_get_attribute_target_names(target);
7563+
if (!(target_type & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL))) {
7564+
zend_string *location = zend_get_attribute_target_names(target_type);
75657565
zend_string *allowed = zend_get_attribute_target_names(config->flags);
75667566

75677567
zend_error_noreturn(E_ERROR, "Attribute \"%s\" cannot target %s (allowed targets: %s)",
@@ -7575,8 +7575,9 @@ static void zend_compile_attributes(
75757575
}
75767576
}
75777577

7578-
if (config->validator != NULL) {
7579-
config->validator(attr, target, CG(active_class_entry));
7578+
/* target is NULL for global constants at compile-time. Validator will be called at runtime. */
7579+
if (config->validator != NULL && target) {
7580+
config->validator(attr, target_type, CG(active_class_entry), target, offset);
75807581
}
75817582
} ZEND_HASH_FOREACH_END();
75827583
}
@@ -7773,13 +7774,6 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
77737774
arg_info->name = zend_string_copy(name);
77747775
arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0);
77757776

7776-
if (attributes_ast) {
7777-
zend_compile_attributes(
7778-
&op_array->attributes, attributes_ast, i + 1, ZEND_ATTRIBUTE_TARGET_PARAMETER,
7779-
is_promoted ? ZEND_ATTRIBUTE_TARGET_PROPERTY : 0
7780-
);
7781-
}
7782-
77837777
bool forced_allow_nullable = false;
77847778
if (type_ast) {
77857779
uint32_t default_type = *default_ast_ptr ? Z_TYPE(default_node.u.constant) : IS_UNDEF;
@@ -7835,6 +7829,13 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
78357829
zval_ptr_dtor(&default_node.u.constant);
78367830
}
78377831

7832+
if (attributes_ast) {
7833+
zend_compile_attributes(
7834+
&op_array->attributes, attributes_ast, i + 1, ZEND_ATTRIBUTE_TARGET_PARAMETER,
7835+
is_promoted ? ZEND_ATTRIBUTE_TARGET_PROPERTY : 0, op_array
7836+
);
7837+
}
7838+
78387839
opline = zend_emit_op(NULL, opcode, NULL, &default_node);
78397840
SET_NODE(opline->result, &var_node);
78407841
opline->op1.num = i + 1;
@@ -7917,12 +7918,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
79177918
}
79187919
if (attributes_ast) {
79197920
zend_compile_attributes(
7920-
&prop->attributes, attributes_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, ZEND_ATTRIBUTE_TARGET_PARAMETER);
7921-
7922-
zend_attribute *override_attribute = zend_get_attribute_str(prop->attributes, "override", sizeof("override")-1);
7923-
if (override_attribute) {
7924-
prop->flags |= ZEND_ACC_OVERRIDE;
7925-
}
7921+
&prop->attributes, attributes_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, ZEND_ATTRIBUTE_TARGET_PARAMETER, prop);
79267922
}
79277923
}
79287924
}
@@ -8429,37 +8425,7 @@ static zend_op_array *zend_compile_func_decl_ex(
84298425
target = ZEND_ATTRIBUTE_TARGET_METHOD;
84308426
}
84318427

8432-
zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target, 0);
8433-
8434-
zend_attribute *override_attribute = zend_get_attribute_str(
8435-
op_array->attributes,
8436-
"override",
8437-
sizeof("override")-1
8438-
);
8439-
8440-
if (override_attribute) {
8441-
op_array->fn_flags |= ZEND_ACC_OVERRIDE;
8442-
}
8443-
8444-
zend_attribute *deprecated_attribute = zend_get_attribute_str(
8445-
op_array->attributes,
8446-
"deprecated",
8447-
sizeof("deprecated")-1
8448-
);
8449-
8450-
if (deprecated_attribute) {
8451-
op_array->fn_flags |= ZEND_ACC_DEPRECATED;
8452-
}
8453-
8454-
zend_attribute *nodiscard_attribute = zend_get_attribute_str(
8455-
op_array->attributes,
8456-
"nodiscard",
8457-
sizeof("nodiscard")-1
8458-
);
8459-
8460-
if (nodiscard_attribute) {
8461-
op_array->fn_flags |= ZEND_ACC_NODISCARD;
8462-
}
8428+
zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target, 0, op_array);
84638429
}
84648430

84658431
/* Do not leak the class scope into free standing functions, even if they are dynamically
@@ -8901,12 +8867,7 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f
89018867
}
89028868

89038869
if (attr_ast) {
8904-
zend_compile_attributes(&info->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, 0);
8905-
8906-
zend_attribute *override_attribute = zend_get_attribute_str(info->attributes, "override", sizeof("override")-1);
8907-
if (override_attribute) {
8908-
info->flags |= ZEND_ACC_OVERRIDE;
8909-
}
8870+
zend_compile_attributes(&info->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, 0, info);
89108871
}
89118872

89128873
CG(context).active_property_info_name = old_active_property_info_name;
@@ -8983,17 +8944,7 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as
89838944
c = zend_declare_typed_class_constant(ce, name, &value_zv, flags, doc_comment, type);
89848945

89858946
if (attr_ast) {
8986-
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
8987-
8988-
zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
8989-
8990-
if (deprecated) {
8991-
ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
8992-
/* For deprecated constants, we need to flag the zval for recursion
8993-
* detection. Make sure the zval is separated out of shm. */
8994-
ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
8995-
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
8996-
}
8947+
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0, c);
89978948
}
89988949
}
89998950
}
@@ -9263,7 +9214,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92639214
CG(active_class_entry) = ce;
92649215

92659216
if (decl->child[3]) {
9266-
zend_compile_attributes(&ce->attributes, decl->child[3], 0, ZEND_ATTRIBUTE_TARGET_CLASS, 0);
9217+
zend_compile_attributes(&ce->attributes, decl->child[3], 0, ZEND_ATTRIBUTE_TARGET_CLASS, 0, ce);
92679218
}
92689219

92699220
if (implements_ast) {
@@ -9440,13 +9391,7 @@ static void zend_compile_enum_case(zend_ast *ast)
94409391

94419392
zend_ast *attr_ast = ast->child[3];
94429393
if (attr_ast) {
9443-
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0);
9444-
9445-
zend_attribute *deprecated = zend_get_attribute_str(c->attributes, "deprecated", sizeof("deprecated")-1);
9446-
9447-
if (deprecated) {
9448-
ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
9449-
}
9394+
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0, c);
94509395
}
94519396
}
94529397

@@ -9660,7 +9605,7 @@ static void zend_compile_const_decl(zend_ast *ast) /* {{{ */
96609605
}
96619606

96629607
HashTable *attributes = NULL;
9663-
zend_compile_attributes(&attributes, list->child[1], 0, ZEND_ATTRIBUTE_TARGET_CONST, 0);
9608+
zend_compile_attributes(&attributes, list->child[1], 0, ZEND_ATTRIBUTE_TARGET_CONST, 0, NULL);
96649609

96659610
ZEND_ASSERT(last_op != NULL);
96669611
last_op->opcode = ZEND_DECLARE_ATTRIBUTED_CONST;

Zend/zend_constants.c

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -561,17 +561,10 @@ void zend_constant_add_attributes(zend_constant *c, HashTable *attributes) {
561561
GC_TRY_ADDREF(attributes);
562562
c->attributes = attributes;
563563

564-
zend_attribute *deprecated_attribute = zend_get_attribute_str(
565-
c->attributes,
566-
"deprecated",
567-
strlen("deprecated")
568-
);
569-
570-
if (deprecated_attribute) {
571-
ZEND_CONSTANT_SET_FLAGS(
572-
c,
573-
ZEND_CONSTANT_FLAGS(c) | CONST_DEPRECATED,
574-
ZEND_CONSTANT_MODULE_NUMBER(c)
575-
);
576-
}
564+
ZEND_HASH_PACKED_FOREACH_PTR(attributes, zend_attribute *attr) {
565+
zend_internal_attribute *config = zend_internal_attribute_get(attr->lcname);
566+
if (config && config->validator != NULL) {
567+
config->validator(attr, ZEND_ATTRIBUTE_TARGET_CONST, CG(active_class_entry), c, 0);
568+
}
569+
} ZEND_HASH_FOREACH_END();
577570
}

0 commit comments

Comments
 (0)