php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_attributes.c
Go to the documentation of this file.
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"
24#include "zend_exceptions.h"
25#include "zend_smart_str.h"
26
34
35static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;
36
37static HashTable internal_attributes;
38
40{
41 // TODO: More proper signature validation: Too many args, incorrect arg names.
42 if (attr->argc > 0) {
43 zval flags;
44
47 return 0;
48 }
49
50 if (Z_TYPE(flags) != IS_LONG) {
52 "Attribute::__construct(): Argument #1 ($flags) must be of type int, %s given",
54 );
56 return 0;
57 }
58
59 uint32_t flags_l = Z_LVAL(flags);
60 if (flags_l & ~ZEND_ATTRIBUTE_FLAGS) {
61 zend_throw_error(NULL, "Invalid attribute flags specified");
62 return 0;
63 }
64
65 return flags_l;
66 }
67
69}
70
71static void validate_allow_dynamic_properties(
72 zend_attribute *attr, uint32_t target, zend_class_entry *scope)
73{
74 if (scope->ce_flags & ZEND_ACC_TRAIT) {
75 zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to trait %s",
76 ZSTR_VAL(scope->name)
77 );
78 }
79 if (scope->ce_flags & ZEND_ACC_INTERFACE) {
80 zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to interface %s",
81 ZSTR_VAL(scope->name)
82 );
83 }
84 if (scope->ce_flags & ZEND_ACC_READONLY_CLASS) {
85 zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to readonly class %s",
86 ZSTR_VAL(scope->name)
87 );
88 }
89 if (scope->ce_flags & ZEND_ACC_ENUM) {
90 zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to enum %s",
91 ZSTR_VAL(scope->name)
92 );
93 }
95}
96
108
113
118
123
134
141
148
149static HashTable *attributes_sensitive_parameter_value_get_properties_for(zend_object *zobj, zend_prop_purpose purpose)
150{
151 return NULL;
152}
153
155{
157}
158
160{
161 zend_string *message = NULL;
162 zend_string *since = NULL;
163 zval value;
164
167 Z_PARAM_STR_OR_NULL(message)
170
171 if (message) {
172 ZVAL_STR(&value, message);
173 } else {
175 }
177
178 /* The assignment might fail due to 'readonly'. */
179 if (UNEXPECTED(EG(exception))) {
181 }
182
183 if (since) {
184 ZVAL_STR(&value, since);
185 } else {
187 }
189
190 /* The assignment might fail due to 'readonly'. */
191 if (UNEXPECTED(EG(exception))) {
193 }
194}
195
196static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
197{
198 if (attributes) {
200
202 if (attr->offset == offset && zend_string_equals(attr->lcname, lcname)) {
203 return attr;
204 }
206 }
207
208 return NULL;
209}
210
211static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
212{
213 if (attributes) {
215
217 if (attr->offset == offset && zend_string_equals_cstr(attr->lcname, str, len)) {
218 return attr;
219 }
221 }
222
223 return NULL;
224}
225
227{
228 return get_attribute(attributes, lcname, 0);
229}
230
231ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len)
232{
233 return get_attribute_str(attributes, str, len, 0);
234}
235
237{
238 return get_attribute(attributes, lcname, offset + 1);
239}
240
241ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
242{
243 return get_attribute_str(attributes, str, len, offset + 1);
244}
245
247{
248 if (i >= attr->argc) {
249 return FAILURE;
250 }
251
252 ZVAL_COPY_OR_DUP(ret, &attr->args[i].value);
253
254 if (Z_TYPE_P(ret) == IS_CONSTANT_AST) {
257 return FAILURE;
258 }
259 }
260
261 return SUCCESS;
262}
263
265{
267
268 if (filename) {
269 /* Set up dummy call frame that makes it look like the attribute was invoked
270 * from where it occurs in the code. */
271 zend_function dummy_func;
272 zend_op *opline;
273
274 memset(&dummy_func, 0, sizeof(zend_function));
275
276 call = zend_vm_stack_push_call_frame_ex(
278 ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op), sizeof(zval)) +
280 0, &dummy_func, 0, NULL);
281
282 opline = (zend_op*)(call + 1);
283 memset(opline, 0, sizeof(zend_op));
284 opline->opcode = ZEND_DO_FCALL;
285 opline->lineno = attribute_data->lineno;
286
287 call->opline = opline;
288 call->call = NULL;
289 call->return_value = NULL;
290 call->func = (zend_function*)(call->opline + 1);
291 call->prev_execute_data = EG(current_execute_data);
292
293 memset(call->func, 0, sizeof(zend_function));
294 call->func->type = ZEND_USER_FUNCTION;
295 call->func->op_array.fn_flags =
297 call->func->op_array.fn_flags |= ZEND_ACC_CALL_VIA_TRAMPOLINE;
298 call->func->op_array.filename = filename;
299
300 EG(current_execute_data) = call;
301 }
302
303 zval *args = NULL;
304 HashTable *named_params = NULL;
305
307
308 uint32_t argc = 0;
309 if (attribute_data->argc) {
310 args = emalloc(attribute_data->argc * sizeof(zval));
311
312 for (uint32_t i = 0; i < attribute_data->argc; i++) {
313 zval val;
314 if (FAILURE == zend_get_attribute_value(&val, attribute_data, i, scope)) {
315 result = FAILURE;
316 goto out;
317 }
318 if (attribute_data->args[i].name) {
319 if (!named_params) {
320 named_params = zend_new_array(0);
321 }
322 zend_hash_add_new(named_params, attribute_data->args[i].name, &val);
323 } else {
324 ZVAL_COPY_VALUE(&args[i], &val);
325 argc++;
326 }
327 }
328 }
329
330 result = object_init_with_constructor(obj, attribute_ce, argc, args, named_params);
331
332 out:
333 for (uint32_t i = 0; i < argc; i++) {
334 zval_ptr_dtor(&args[i]);
335 }
336
337 efree(args);
338
339 if (named_params) {
340 zend_array_destroy(named_params);
341 }
342
343 if (filename) {
344 EG(current_execute_data) = call->prev_execute_data;
345 zend_vm_stack_free_call_frame(call);
346 }
347
348 return result;
349}
350
351static const char *target_names[] = {
352 "class",
353 "function",
354 "method",
355 "property",
356 "class constant",
357 "parameter"
358};
359
361{
362 smart_str str = { 0 };
363
364 for (uint32_t i = 0; i < (sizeof(target_names) / sizeof(char *)); i++) {
365 if (flags & (1 << i)) {
366 if (smart_str_get_len(&str)) {
367 smart_str_appends(&str, ", ");
368 }
369
370 smart_str_appends(&str, target_names[i]);
371 }
372 }
373
374 return smart_str_extract(&str);
375}
376
378{
379 zend_attribute *other;
380
381 ZEND_HASH_PACKED_FOREACH_PTR(attributes, other) {
382 if (other != attr && other->offset == attr->offset) {
383 if (zend_string_equals(other->lcname, attr->lcname)) {
384 return 1;
385 }
386 }
388
389 return 0;
390}
391
392static void attr_free(zval *v)
393{
396
397 zend_string_release(attr->name);
398 zend_string_release(attr->lcname);
399
400 for (uint32_t i = 0; i < attr->argc; i++) {
401 if (attr->args[i].name) {
402 zend_string_release(attr->args[i].name);
403 }
404 if (persistent) {
405 zval_internal_ptr_dtor(&attr->args[i].value);
406 } else {
407 zval_ptr_dtor(&attr->args[i].value);
408 }
409 }
410
412}
413
414ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_string *name, uint32_t argc, uint32_t flags, uint32_t offset, uint32_t lineno)
415{
417 if (*attributes == NULL) {
418 *attributes = pemalloc(sizeof(HashTable), persistent);
419 zend_hash_init(*attributes, 8, NULL, attr_free, persistent);
420 }
421
423
424 if (persistent == ((GC_FLAGS(name) & IS_STR_PERSISTENT) != 0)) {
425 attr->name = zend_string_copy(name);
426 } else {
427 attr->name = zend_string_dup(name, persistent);
428 }
429
430 attr->lcname = zend_string_tolower_ex(attr->name, persistent);
431 attr->flags = flags;
432 attr->lineno = lineno;
433 attr->offset = offset;
434 attr->argc = argc;
435
436 /* Initialize arguments to avoid partial initialization in case of fatal errors. */
437 for (uint32_t i = 0; i < argc; i++) {
438 attr->args[i].name = NULL;
439 ZVAL_UNDEF(&attr->args[i].value);
440 }
441
442 zend_hash_next_index_insert_ptr(*attributes, attr);
443
444 return attr;
445}
446
447static void free_internal_attribute(zval *v)
448{
449 pefree(Z_PTR_P(v), 1);
450}
451
453{
454 zend_internal_attribute *internal_attr;
456
457 if (ce->type != ZEND_INTERNAL_CLASS) {
458 zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
459 }
460
462 if (zend_string_equals(attr->name, zend_ce_attribute->name)) {
463 internal_attr = pemalloc(sizeof(zend_internal_attribute), 1);
464 internal_attr->ce = ce;
465 internal_attr->flags = Z_LVAL(attr->args[0].value);
466 internal_attr->validator = NULL;
467
469 zend_hash_update_ptr(&internal_attributes, lcname, internal_attr);
470 zend_string_release(lcname);
471
472 return internal_attr;
473 }
475
476 zend_error_noreturn(E_ERROR, "Classes must be first marked as attribute before being able to be registered as internal attribute class");
477}
478
480{
481 zend_attribute *attr = zend_add_class_attribute(ce, zend_ce_attribute->name, 1);
482 ZVAL_LONG(&attr->args[0].value, flags);
483
485}
486
488{
489 return zend_hash_find_ptr(&internal_attributes, lcname);
490}
491
493{
495
496 zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1);
497
498 zend_ce_attribute = register_class_Attribute();
500
501 zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange();
503
504 zend_ce_allow_dynamic_properties = register_class_AllowDynamicProperties();
506 attr->validator = validate_allow_dynamic_properties;
507
508 zend_ce_sensitive_parameter = register_class_SensitiveParameter();
510
511 memcpy(&attributes_object_handlers_sensitive_parameter_value, &std_object_handlers, sizeof(zend_object_handlers));
512 attributes_object_handlers_sensitive_parameter_value.get_properties_for = attributes_sensitive_parameter_value_get_properties_for;
513
514 /* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */
515 zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue();
516 zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value;
517
518 zend_ce_override = register_class_Override();
520
521 zend_ce_deprecated = register_class_Deprecated();
523}
524
526{
527 zend_hash_destroy(&internal_attributes);
528}
size_t len
Definition apprentice.c:174
bool exception
Definition assert.c:30
uint32_t v
Definition cdf.c:1237
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
new_type attr
Definition ffi.c:4364
zval * val
Definition ffi.c:4262
ffi persistent
Definition ffi.c:3633
zend_long offset
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
zend_string * lcname
#define get_attribute(node, name)
Definition php_xml.h:22
zend_attribute_arg args[1]
zend_string * lcname
zend_string * name
Definition zend.h:149
char type
Definition zend.h:148
HashTable * attributes
Definition zend.h:219
zend_class_entry * ce
void(* validator)(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
uint8_t opcode
uint32_t lineno
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format,...)
Definition zend.c:1703
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API const char * zend_zval_value_name(const zval *arg)
Definition zend_API.c:148
ZEND_API zend_result object_init_with_constructor(zval *arg, zend_class_entry *class_type, uint32_t param_count, zval *params, HashTable *named_params)
Definition zend_API.c:1855
ZEND_API void zend_update_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zval *value)
Definition zend_API.c:4979
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define Z_PARAM_STR_OR_NULL(dest)
Definition zend_API.h:2089
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define ZEND_METHOD(classname, name)
Definition zend_API.h:76
#define RETURN_THROWS()
Definition zend_API.h:1060
#define ZEND_THIS
Definition zend_API.h:523
#define RETURN_EMPTY_ARRAY()
Definition zend_API.h:1051
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define ZEND_MM_ALIGNED_SIZE_EX(size, alignment)
Definition zend_alloc.h:37
#define efree(ptr)
Definition zend_alloc.h:155
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define emalloc(size)
Definition zend_alloc.h:151
ZEND_API zend_internal_attribute * zend_internal_attribute_get(zend_string *lcname)
ZEND_API zend_internal_attribute * zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
ZEND_API zend_class_entry * zend_ce_override
ZEND_API zend_class_entry * zend_ce_sensitive_parameter_value
ZEND_API zend_attribute * zend_add_attribute(HashTable **attributes, zend_string *name, uint32_t argc, uint32_t flags, uint32_t offset, uint32_t lineno)
ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, uint32_t i, zend_class_entry *scope)
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)
ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr)
void zend_attributes_shutdown(void)
ZEND_API zend_class_entry * zend_ce_sensitive_parameter
ZEND_API zend_attribute * zend_get_attribute(HashTable *attributes, zend_string *lcname)
ZEND_API zend_class_entry * zend_ce_allow_dynamic_properties
uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_entry *scope)
ZEND_API zend_attribute * zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
ZEND_API zend_string * zend_get_attribute_target_names(uint32_t flags)
ZEND_API zend_class_entry * zend_ce_attribute
ZEND_API zend_attribute * zend_get_attribute_str(HashTable *attributes, const char *str, size_t len)
void zend_register_attribute_ce(void)
ZEND_API zend_attribute * zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
ZEND_API zend_class_entry * zend_ce_return_type_will_change_attribute
ZEND_API zend_class_entry * zend_ce_deprecated
ZEND_API zend_internal_attribute * zend_mark_internal_attribute(zend_class_entry *ce)
#define ZEND_ATTRIBUTE_FLAGS
#define ZEND_ATTRIBUTE_TARGET_ALL
#define ZEND_ATTRIBUTE_SIZE(argc)
struct _zend_attribute zend_attribute
struct _zend_internal_attribute zend_internal_attribute
#define ZEND_ATTRIBUTE_STRICT_TYPES
#define ZEND_ATTRIBUTE_PERSISTENT
struct _zval_struct zval
zval * args
#define ZEND_ACC_ENUM
struct _zend_op zend_op
#define OBJ_PROP_NUM(obj, num)
#define ZEND_ACC_STRICT_TYPES
#define ZEND_USER_FUNCTION
#define ZEND_ACC_INTERFACE
#define ZEND_ACC_CALL_VIA_TRAMPOLINE
#define ZEND_ACC_READONLY_CLASS
#define ZEND_ACC_TRAIT
#define ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES
#define ZEND_INTERNAL_CLASS
#define ZEND_API
#define E_ERROR
Definition zend_errors.h:23
ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *pp, zend_class_entry *scope)
union _zend_function zend_function
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zval *ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:1007
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
Definition zend_hash.c:1808
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_PACKED_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1487
#define ZEND_HASH_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1118
#define zend_new_array(size)
Definition zend_hash.h:338
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
int32_t zend_long
Definition zend_long.h:42
struct _zend_string zend_string
ZEND_API const zend_object_handlers std_object_handlers
enum _zend_prop_purpose zend_prop_purpose
ZEND_API zend_string *ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent)
#define ZEND_ASSERT(c)
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_KNOWN(idx)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_STR(z, s)
#define ZVAL_UNDEF(z)
#define ZVAL_NULL(z)
#define ZVAL_LONG(z, l)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define ZVAL_COPY_OR_DUP(z, v)
#define Z_PTR_P(zval_p)
#define GC_FLAGS(p)
Definition zend_types.h:756
@ FAILURE
Definition zend_types.h:61
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_COPY(z, v)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define IS_CONSTANT_AST
Definition zend_types.h:611
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_TYPE(zval)
Definition zend_types.h:659
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define ZVAL_COPY_VALUE(z, v)
#define Z_LVAL(zval)
Definition zend_types.h:965
#define IS_STR_PERSISTENT
Definition zend_types.h:818
ZEND_API void zval_internal_ptr_dtor(zval *zval_ptr)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval * return_value
zend_string * name
bool result
zval * ret
value
zend_execute_data * call
new_op_array scope
zend_object * zobj
out($f, $s)
#define ZEND_DO_FCALL