/src/php-src/Zend/zend_attributes.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend Engine | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | |
6 | | +----------------------------------------------------------------------+ |
7 | | | This source file is subject to version 2.00 of the Zend license, | |
8 | | | that is bundled with this package in the file LICENSE, and is | |
9 | | | available through the world-wide-web at the following url: | |
10 | | | http://www.zend.com/license/2_00.txt. | |
11 | | | If you did not receive a copy of the Zend license and are unable to | |
12 | | | obtain it through the world-wide-web, please send a note to | |
13 | | | license@zend.com so we can mail you a copy immediately. | |
14 | | +----------------------------------------------------------------------+ |
15 | | | Authors: Benjamin Eberlei <kontakt@beberlei.de> | |
16 | | | Martin Schröder <m.schroeder2007@gmail.com> | |
17 | | +----------------------------------------------------------------------+ |
18 | | */ |
19 | | |
20 | | #include "zend.h" |
21 | | #include "zend_API.h" |
22 | | #include "zend_attributes.h" |
23 | | #include "zend_attributes_arginfo.h" |
24 | | #include "zend_exceptions.h" |
25 | | #include "zend_smart_str.h" |
26 | | |
27 | | ZEND_API zend_class_entry *zend_ce_attribute; |
28 | | ZEND_API zend_class_entry *zend_ce_return_type_will_change_attribute; |
29 | | ZEND_API zend_class_entry *zend_ce_allow_dynamic_properties; |
30 | | ZEND_API zend_class_entry *zend_ce_sensitive_parameter; |
31 | | ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; |
32 | | ZEND_API zend_class_entry *zend_ce_override; |
33 | | ZEND_API zend_class_entry *zend_ce_deprecated; |
34 | | ZEND_API zend_class_entry *zend_ce_nodiscard; |
35 | | |
36 | | static zend_object_handlers attributes_object_handlers_sensitive_parameter_value; |
37 | | |
38 | | static HashTable internal_attributes; |
39 | | |
40 | | uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_entry *scope) |
41 | 263 | { |
42 | | // TODO: More proper signature validation: Too many args, incorrect arg names. |
43 | 263 | if (attr->argc > 0) { |
44 | 190 | zval flags; |
45 | | |
46 | 190 | if (FAILURE == zend_get_attribute_value(&flags, attr, 0, scope)) { |
47 | 5 | ZEND_ASSERT(EG(exception)); |
48 | 5 | return 0; |
49 | 5 | } |
50 | | |
51 | 185 | if (Z_TYPE(flags) != IS_LONG) { |
52 | 5 | zend_throw_error(NULL, |
53 | 5 | "Attribute::__construct(): Argument #1 ($flags) must be of type int, %s given", |
54 | 5 | zend_zval_value_name(&flags) |
55 | 5 | ); |
56 | 5 | zval_ptr_dtor(&flags); |
57 | 5 | return 0; |
58 | 5 | } |
59 | | |
60 | 180 | uint32_t flags_l = Z_LVAL(flags); |
61 | 180 | if (flags_l & ~ZEND_ATTRIBUTE_FLAGS) { |
62 | 5 | zend_throw_error(NULL, "Invalid attribute flags specified"); |
63 | 5 | return 0; |
64 | 5 | } |
65 | | |
66 | 175 | return flags_l; |
67 | 180 | } |
68 | | |
69 | 73 | return ZEND_ATTRIBUTE_TARGET_ALL; |
70 | 263 | } |
71 | | |
72 | | static void validate_allow_dynamic_properties( |
73 | | zend_attribute *attr, uint32_t target, zend_class_entry *scope) |
74 | 481 | { |
75 | 481 | if (scope->ce_flags & ZEND_ACC_TRAIT) { |
76 | 6 | zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to trait %s", |
77 | 6 | ZSTR_VAL(scope->name) |
78 | 6 | ); |
79 | 6 | } |
80 | 475 | if (scope->ce_flags & ZEND_ACC_INTERFACE) { |
81 | 6 | zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to interface %s", |
82 | 6 | ZSTR_VAL(scope->name) |
83 | 6 | ); |
84 | 6 | } |
85 | 469 | if (scope->ce_flags & ZEND_ACC_READONLY_CLASS) { |
86 | 11 | zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to readonly class %s", |
87 | 11 | ZSTR_VAL(scope->name) |
88 | 11 | ); |
89 | 11 | } |
90 | 458 | if (scope->ce_flags & ZEND_ACC_ENUM) { |
91 | 6 | zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to enum %s", |
92 | 6 | ZSTR_VAL(scope->name) |
93 | 6 | ); |
94 | 6 | } |
95 | 452 | scope->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; |
96 | 452 | } |
97 | | |
98 | | ZEND_METHOD(Attribute, __construct) |
99 | 15 | { |
100 | 15 | zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL; |
101 | | |
102 | 45 | ZEND_PARSE_PARAMETERS_START(0, 1) |
103 | 45 | Z_PARAM_OPTIONAL |
104 | 50 | Z_PARAM_LONG(flags) |
105 | 15 | ZEND_PARSE_PARAMETERS_END(); |
106 | | |
107 | 15 | ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), flags); |
108 | 15 | } |
109 | | |
110 | | ZEND_METHOD(ReturnTypeWillChange, __construct) |
111 | 5 | { |
112 | 5 | ZEND_PARSE_PARAMETERS_NONE(); |
113 | 5 | } |
114 | | |
115 | | ZEND_METHOD(AllowDynamicProperties, __construct) |
116 | 5 | { |
117 | 5 | ZEND_PARSE_PARAMETERS_NONE(); |
118 | 5 | } |
119 | | |
120 | | ZEND_METHOD(SensitiveParameter, __construct) |
121 | 5 | { |
122 | 5 | ZEND_PARSE_PARAMETERS_NONE(); |
123 | 5 | } |
124 | | |
125 | | ZEND_METHOD(SensitiveParameterValue, __construct) |
126 | 440 | { |
127 | 440 | zval *value; |
128 | | |
129 | 1.31k | ZEND_PARSE_PARAMETERS_START(1, 1) |
130 | 1.74k | Z_PARAM_ZVAL(value) |
131 | 1.74k | ZEND_PARSE_PARAMETERS_END(); |
132 | | |
133 | 435 | zend_update_property_ex(zend_ce_sensitive_parameter_value, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_VALUE), value); |
134 | 435 | } |
135 | | |
136 | | ZEND_METHOD(SensitiveParameterValue, getValue) |
137 | 52 | { |
138 | 52 | ZEND_PARSE_PARAMETERS_NONE(); |
139 | | |
140 | 52 | ZVAL_COPY(return_value, OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0)); |
141 | 52 | } |
142 | | |
143 | | ZEND_METHOD(SensitiveParameterValue, __debugInfo) |
144 | 0 | { |
145 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
146 | | |
147 | 0 | RETURN_EMPTY_ARRAY(); |
148 | 0 | } |
149 | | |
150 | | static HashTable *attributes_sensitive_parameter_value_get_properties_for(zend_object *zobj, zend_prop_purpose purpose) |
151 | 217 | { |
152 | 217 | return NULL; |
153 | 217 | } |
154 | | |
155 | | ZEND_METHOD(Override, __construct) |
156 | 5 | { |
157 | 5 | ZEND_PARSE_PARAMETERS_NONE(); |
158 | 5 | } |
159 | | |
160 | | ZEND_METHOD(Deprecated, __construct) |
161 | 348 | { |
162 | 348 | zend_string *message = NULL; |
163 | 348 | zend_string *since = NULL; |
164 | 348 | zval value; |
165 | | |
166 | 1.04k | ZEND_PARSE_PARAMETERS_START(0, 2) |
167 | 1.04k | Z_PARAM_OPTIONAL |
168 | 1.38k | Z_PARAM_STR_OR_NULL(message) |
169 | 1.22k | Z_PARAM_STR_OR_NULL(since) |
170 | 348 | ZEND_PARSE_PARAMETERS_END(); |
171 | | |
172 | 331 | if (message) { |
173 | 271 | ZVAL_STR(&value, message); |
174 | 271 | } else { |
175 | 60 | ZVAL_NULL(&value); |
176 | 60 | } |
177 | 331 | zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value); |
178 | | |
179 | | /* The assignment might fail due to 'readonly'. */ |
180 | 331 | if (UNEXPECTED(EG(exception))) { |
181 | 5 | RETURN_THROWS(); |
182 | 5 | } |
183 | | |
184 | 326 | if (since) { |
185 | 125 | ZVAL_STR(&value, since); |
186 | 201 | } else { |
187 | 201 | ZVAL_NULL(&value); |
188 | 201 | } |
189 | 326 | zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_SINCE), &value); |
190 | | |
191 | | /* The assignment might fail due to 'readonly'. */ |
192 | 326 | if (UNEXPECTED(EG(exception))) { |
193 | 0 | RETURN_THROWS(); |
194 | 0 | } |
195 | 326 | } |
196 | | |
197 | | ZEND_METHOD(NoDiscard, __construct) |
198 | 43 | { |
199 | 43 | zend_string *message = NULL; |
200 | 43 | zval value; |
201 | | |
202 | 129 | ZEND_PARSE_PARAMETERS_START(0, 1) |
203 | 129 | Z_PARAM_OPTIONAL |
204 | 162 | Z_PARAM_STR_OR_NULL(message) |
205 | 43 | ZEND_PARSE_PARAMETERS_END(); |
206 | | |
207 | 38 | if (message) { |
208 | 33 | ZVAL_STR(&value, message); |
209 | 33 | } else { |
210 | 5 | ZVAL_NULL(&value); |
211 | 5 | } |
212 | 38 | zend_update_property_ex(zend_ce_nodiscard, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value); |
213 | | |
214 | | /* The assignment might fail due to 'readonly'. */ |
215 | 38 | if (UNEXPECTED(EG(exception))) { |
216 | 5 | RETURN_THROWS(); |
217 | 5 | } |
218 | 38 | } |
219 | | |
220 | | static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) |
221 | 0 | { |
222 | 0 | if (attributes) { |
223 | 0 | zend_attribute *attr; |
224 | |
|
225 | 0 | ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) { |
226 | 0 | if (attr->offset == offset && zend_string_equals(attr->lcname, lcname)) { |
227 | 0 | return attr; |
228 | 0 | } |
229 | 0 | } ZEND_HASH_FOREACH_END(); |
230 | 0 | } |
231 | | |
232 | 0 | return NULL; |
233 | 0 | } |
234 | | |
235 | | static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset) |
236 | 1.56M | { |
237 | 1.56M | if (attributes) { |
238 | 16.3k | zend_attribute *attr; |
239 | | |
240 | 175k | ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) { |
241 | 175k | if (attr->offset == offset && zend_string_equals_cstr(attr->lcname, str, len)) { |
242 | 2.22k | return attr; |
243 | 2.22k | } |
244 | 175k | } ZEND_HASH_FOREACH_END(); |
245 | 16.3k | } |
246 | | |
247 | 1.56M | return NULL; |
248 | 1.56M | } |
249 | | |
250 | | ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname) |
251 | 0 | { |
252 | 0 | return get_attribute(attributes, lcname, 0); |
253 | 0 | } |
254 | | |
255 | | ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len) |
256 | 16.0k | { |
257 | 16.0k | return get_attribute_str(attributes, str, len, 0); |
258 | 16.0k | } |
259 | | |
260 | | ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) |
261 | 0 | { |
262 | 0 | return get_attribute(attributes, lcname, offset + 1); |
263 | 0 | } |
264 | | |
265 | | ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset) |
266 | 1.55M | { |
267 | 1.55M | return get_attribute_str(attributes, str, len, offset + 1); |
268 | 1.55M | } |
269 | | |
270 | | ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, uint32_t i, zend_class_entry *scope) |
271 | 1.40k | { |
272 | 1.40k | if (i >= attr->argc) { |
273 | 0 | return FAILURE; |
274 | 0 | } |
275 | | |
276 | 1.40k | ZVAL_COPY_OR_DUP(ret, &attr->args[i].value); |
277 | | |
278 | 1.40k | if (Z_TYPE_P(ret) == IS_CONSTANT_AST) { |
279 | 471 | if (SUCCESS != zval_update_constant_ex(ret, scope)) { |
280 | 39 | zval_ptr_dtor(ret); |
281 | 39 | return FAILURE; |
282 | 39 | } |
283 | 471 | } |
284 | | |
285 | 1.36k | return SUCCESS; |
286 | 1.40k | } |
287 | | |
288 | | ZEND_API zend_result zend_get_attribute_object(zval *obj, zend_class_entry *attribute_ce, zend_attribute *attribute_data, zend_class_entry *scope, zend_string *filename) |
289 | 589 | { |
290 | 589 | zend_execute_data *call = NULL; |
291 | | |
292 | 589 | if (filename) { |
293 | | /* Set up dummy call frame that makes it look like the attribute was invoked |
294 | | * from where it occurs in the code. */ |
295 | 226 | zend_function dummy_func; |
296 | 226 | zend_op *opline; |
297 | | |
298 | 226 | memset(&dummy_func, 0, sizeof(zend_function)); |
299 | | |
300 | 226 | call = zend_vm_stack_push_call_frame_ex( |
301 | 226 | ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_execute_data), sizeof(zval)) + |
302 | 226 | ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op), sizeof(zval)) + |
303 | 226 | ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_function), sizeof(zval)), |
304 | 226 | 0, &dummy_func, 0, NULL); |
305 | | |
306 | 226 | opline = (zend_op*)(call + 1); |
307 | 226 | memset(opline, 0, sizeof(zend_op)); |
308 | 226 | opline->opcode = ZEND_DO_FCALL; |
309 | 226 | opline->lineno = attribute_data->lineno; |
310 | | |
311 | 226 | call->opline = opline; |
312 | 226 | call->call = NULL; |
313 | 226 | call->return_value = NULL; |
314 | 226 | call->func = (zend_function*)(call->opline + 1); |
315 | 226 | call->prev_execute_data = EG(current_execute_data); |
316 | | |
317 | 226 | memset(call->func, 0, sizeof(zend_function)); |
318 | 226 | call->func->type = ZEND_USER_FUNCTION; |
319 | 226 | call->func->op_array.fn_flags = |
320 | 226 | attribute_data->flags & ZEND_ATTRIBUTE_STRICT_TYPES ? ZEND_ACC_STRICT_TYPES : 0; |
321 | 226 | call->func->op_array.fn_flags |= ZEND_ACC_CALL_VIA_TRAMPOLINE; |
322 | 226 | call->func->op_array.filename = filename; |
323 | | |
324 | 226 | EG(current_execute_data) = call; |
325 | 226 | } |
326 | | |
327 | 589 | zval *args = NULL; |
328 | 589 | HashTable *named_params = NULL; |
329 | | |
330 | 589 | zend_result result = FAILURE; |
331 | | |
332 | 589 | uint32_t argc = 0; |
333 | 589 | if (attribute_data->argc) { |
334 | 476 | args = emalloc(attribute_data->argc * sizeof(zval)); |
335 | | |
336 | 1.01k | for (uint32_t i = 0; i < attribute_data->argc; i++) { |
337 | 556 | zval val; |
338 | 556 | if (FAILURE == zend_get_attribute_value(&val, attribute_data, i, scope)) { |
339 | 20 | result = FAILURE; |
340 | 20 | goto out; |
341 | 20 | } |
342 | 536 | if (attribute_data->args[i].name) { |
343 | 207 | if (!named_params) { |
344 | 145 | named_params = zend_new_array(0); |
345 | 145 | } |
346 | 207 | zend_hash_add_new(named_params, attribute_data->args[i].name, &val); |
347 | 329 | } else { |
348 | 329 | ZVAL_COPY_VALUE(&args[i], &val); |
349 | 329 | argc++; |
350 | 329 | } |
351 | 536 | } |
352 | 476 | } |
353 | | |
354 | 569 | result = object_init_with_constructor(obj, attribute_ce, argc, args, named_params); |
355 | | |
356 | 589 | out: |
357 | 918 | for (uint32_t i = 0; i < argc; i++) { |
358 | 329 | zval_ptr_dtor(&args[i]); |
359 | 329 | } |
360 | | |
361 | 589 | efree(args); |
362 | | |
363 | 589 | if (named_params) { |
364 | 145 | zend_array_destroy(named_params); |
365 | 145 | } |
366 | | |
367 | 589 | if (filename) { |
368 | 226 | EG(current_execute_data) = call->prev_execute_data; |
369 | 226 | zend_vm_stack_free_call_frame(call); |
370 | 226 | } |
371 | | |
372 | 589 | return result; |
373 | 569 | } |
374 | | |
375 | | static const char *target_names[] = { |
376 | | "class", |
377 | | "function", |
378 | | "method", |
379 | | "property", |
380 | | "class constant", |
381 | | "parameter", |
382 | | "constant" |
383 | | }; |
384 | | |
385 | | ZEND_API zend_string *zend_get_attribute_target_names(uint32_t flags) |
386 | 124 | { |
387 | 124 | smart_str str = { 0 }; |
388 | | |
389 | 992 | for (uint32_t i = 0; i < (sizeof(target_names) / sizeof(char *)); i++) { |
390 | 868 | if (flags & (1 << i)) { |
391 | 160 | if (smart_str_get_len(&str)) { |
392 | 36 | smart_str_appends(&str, ", "); |
393 | 36 | } |
394 | | |
395 | 160 | smart_str_appends(&str, target_names[i]); |
396 | 160 | } |
397 | 868 | } |
398 | | |
399 | 124 | return smart_str_extract(&str); |
400 | 124 | } |
401 | | |
402 | | ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr) |
403 | 1.99k | { |
404 | 1.99k | zend_attribute *other; |
405 | | |
406 | 9.45k | ZEND_HASH_PACKED_FOREACH_PTR(attributes, other) { |
407 | 9.45k | if (other != attr && other->offset == attr->offset) { |
408 | 636 | if (zend_string_equals(other->lcname, attr->lcname)) { |
409 | 48 | return 1; |
410 | 48 | } |
411 | 636 | } |
412 | 9.45k | } ZEND_HASH_FOREACH_END(); |
413 | | |
414 | 1.95k | return 0; |
415 | 1.99k | } |
416 | | |
417 | | static void attr_free(zval *v) |
418 | 27.1k | { |
419 | 27.1k | zend_attribute *attr = Z_PTR_P(v); |
420 | 27.1k | bool persistent = attr->flags & ZEND_ATTRIBUTE_PERSISTENT; |
421 | | |
422 | 27.1k | zend_string_release(attr->name); |
423 | 27.1k | zend_string_release(attr->lcname); |
424 | | |
425 | 45.1k | for (uint32_t i = 0; i < attr->argc; i++) { |
426 | 17.9k | if (attr->args[i].name) { |
427 | 1.90k | zend_string_release(attr->args[i].name); |
428 | 1.90k | } |
429 | 17.9k | if (persistent) { |
430 | 0 | zval_internal_ptr_dtor(&attr->args[i].value); |
431 | 17.9k | } else { |
432 | 17.9k | zval_ptr_dtor(&attr->args[i].value); |
433 | 17.9k | } |
434 | 17.9k | } |
435 | | |
436 | 27.1k | pefree(attr, persistent); |
437 | 27.1k | } |
438 | | |
439 | | ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_string *name, uint32_t argc, uint32_t flags, uint32_t offset, uint32_t lineno) |
440 | 31.3k | { |
441 | 31.3k | bool persistent = flags & ZEND_ATTRIBUTE_PERSISTENT; |
442 | 31.3k | if (*attributes == NULL) { |
443 | 9.26k | *attributes = pemalloc(sizeof(HashTable), persistent); |
444 | 9.26k | zend_hash_init(*attributes, 8, NULL, attr_free, persistent); |
445 | 9.26k | } |
446 | | |
447 | 31.3k | zend_attribute *attr = pemalloc(ZEND_ATTRIBUTE_SIZE(argc), persistent); |
448 | | |
449 | 31.3k | if (persistent == ((GC_FLAGS(name) & IS_STR_PERSISTENT) != 0)) { |
450 | 29.2k | attr->name = zend_string_copy(name); |
451 | 29.2k | } else { |
452 | 2.16k | attr->name = zend_string_dup(name, persistent); |
453 | 2.16k | } |
454 | | |
455 | 31.3k | attr->lcname = zend_string_tolower_ex(attr->name, persistent); |
456 | 31.3k | attr->flags = flags; |
457 | 31.3k | attr->lineno = lineno; |
458 | 31.3k | attr->offset = offset; |
459 | 31.3k | attr->argc = argc; |
460 | | |
461 | | /* Initialize arguments to avoid partial initialization in case of fatal errors. */ |
462 | 51.8k | for (uint32_t i = 0; i < argc; i++) { |
463 | 20.4k | attr->args[i].name = NULL; |
464 | 20.4k | ZVAL_UNDEF(&attr->args[i].value); |
465 | 20.4k | } |
466 | | |
467 | 31.3k | zend_hash_next_index_insert_ptr(*attributes, attr); |
468 | | |
469 | 31.3k | return attr; |
470 | 31.3k | } |
471 | | |
472 | | static void free_internal_attribute(zval *v) |
473 | 0 | { |
474 | 0 | pefree(Z_PTR_P(v), 1); |
475 | 0 | } |
476 | | |
477 | | ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce) |
478 | 112 | { |
479 | 112 | zend_internal_attribute *internal_attr; |
480 | 112 | zend_attribute *attr; |
481 | | |
482 | 112 | if (ce->type != ZEND_INTERNAL_CLASS) { |
483 | 0 | zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute"); |
484 | 0 | } |
485 | | |
486 | 336 | ZEND_HASH_FOREACH_PTR(ce->attributes, attr) { |
487 | 336 | if (zend_string_equals(attr->name, zend_ce_attribute->name)) { |
488 | 112 | internal_attr = pemalloc(sizeof(zend_internal_attribute), 1); |
489 | 112 | internal_attr->ce = ce; |
490 | 112 | internal_attr->flags = Z_LVAL(attr->args[0].value); |
491 | 112 | internal_attr->validator = NULL; |
492 | | |
493 | 112 | zend_string *lcname = zend_string_tolower_ex(ce->name, 1); |
494 | 112 | zend_hash_update_ptr(&internal_attributes, lcname, internal_attr); |
495 | 112 | zend_string_release(lcname); |
496 | | |
497 | 112 | return internal_attr; |
498 | 112 | } |
499 | 336 | } ZEND_HASH_FOREACH_END(); |
500 | | |
501 | 0 | zend_error_noreturn(E_ERROR, "Classes must be first marked as attribute before being able to be registered as internal attribute class"); |
502 | 112 | } |
503 | | |
504 | | ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags) |
505 | 0 | { |
506 | 0 | zend_attribute *attr = zend_add_class_attribute(ce, zend_ce_attribute->name, 1); |
507 | 0 | ZVAL_LONG(&attr->args[0].value, flags); |
508 | |
|
509 | 0 | return zend_mark_internal_attribute(ce); |
510 | 0 | } |
511 | | |
512 | | ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname) |
513 | 60.5k | { |
514 | 60.5k | return zend_hash_find_ptr(&internal_attributes, lcname); |
515 | 60.5k | } |
516 | | |
517 | | void zend_register_attribute_ce(void) |
518 | 16 | { |
519 | 16 | zend_internal_attribute *attr; |
520 | | |
521 | 16 | zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1); |
522 | | |
523 | 16 | zend_ce_attribute = register_class_Attribute(); |
524 | 16 | attr = zend_mark_internal_attribute(zend_ce_attribute); |
525 | | |
526 | 16 | zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange(); |
527 | 16 | zend_mark_internal_attribute(zend_ce_return_type_will_change_attribute); |
528 | | |
529 | 16 | zend_ce_allow_dynamic_properties = register_class_AllowDynamicProperties(); |
530 | 16 | attr = zend_mark_internal_attribute(zend_ce_allow_dynamic_properties); |
531 | 16 | attr->validator = validate_allow_dynamic_properties; |
532 | | |
533 | 16 | zend_ce_sensitive_parameter = register_class_SensitiveParameter(); |
534 | 16 | zend_mark_internal_attribute(zend_ce_sensitive_parameter); |
535 | | |
536 | 16 | memcpy(&attributes_object_handlers_sensitive_parameter_value, &std_object_handlers, sizeof(zend_object_handlers)); |
537 | 16 | attributes_object_handlers_sensitive_parameter_value.get_properties_for = attributes_sensitive_parameter_value_get_properties_for; |
538 | | |
539 | | /* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */ |
540 | 16 | zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue(); |
541 | 16 | zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value; |
542 | | |
543 | 16 | zend_ce_override = register_class_Override(); |
544 | 16 | zend_mark_internal_attribute(zend_ce_override); |
545 | | |
546 | 16 | zend_ce_deprecated = register_class_Deprecated(); |
547 | 16 | attr = zend_mark_internal_attribute(zend_ce_deprecated); |
548 | | |
549 | 16 | zend_ce_nodiscard = register_class_NoDiscard(); |
550 | 16 | attr = zend_mark_internal_attribute(zend_ce_nodiscard); |
551 | 16 | } |
552 | | |
553 | | void zend_attributes_shutdown(void) |
554 | 0 | { |
555 | 0 | zend_hash_destroy(&internal_attributes); |
556 | 0 | } |