Coverage Report

Created: 2025-11-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/Zend/zend_attributes.c
Line
Count
Source
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
ZEND_API zend_class_entry *zend_ce_delayed_target_validation;
36
37
static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;
38
39
static HashTable internal_attributes;
40
41
uint32_t zend_attribute_attribute_get_flags(const zend_attribute *attr, zend_class_entry *scope)
42
389
{
43
  // TODO: More proper signature validation: Too many args, incorrect arg names.
44
389
  if (attr->argc > 0) {
45
312
    zval flags;
46
47
312
    if (FAILURE == zend_get_attribute_value(&flags, attr, 0, scope)) {
48
5
      ZEND_ASSERT(EG(exception));
49
5
      return 0;
50
5
    }
51
52
307
    if (Z_TYPE(flags) != IS_LONG) {
53
9
      zend_throw_error(NULL,
54
9
        "Attribute::__construct(): Argument #1 ($flags) must be of type int, %s given",
55
9
        zend_zval_value_name(&flags)
56
9
      );
57
9
      zval_ptr_dtor(&flags);
58
9
      return 0;
59
9
    }
60
61
298
    uint32_t flags_l = Z_LVAL(flags);
62
298
    if (flags_l & ~ZEND_ATTRIBUTE_FLAGS) {
63
5
      zend_throw_error(NULL, "Invalid attribute flags specified");
64
5
      return 0;
65
5
    }
66
67
293
    return flags_l;
68
298
  }
69
70
77
  return ZEND_ATTRIBUTE_TARGET_ALL;
71
389
}
72
73
static zend_string *validate_allow_dynamic_properties(
74
    zend_attribute *attr, uint32_t target, zend_class_entry *scope)
75
661
{
76
661
  ZEND_ASSERT(scope != NULL);
77
661
  const char *msg = NULL;
78
661
  if (scope->ce_flags & ZEND_ACC_TRAIT) {
79
39
    msg = "Cannot apply #[\\AllowDynamicProperties] to trait %s";
80
622
  } else if (scope->ce_flags & ZEND_ACC_INTERFACE) {
81
54
    msg = "Cannot apply #[\\AllowDynamicProperties] to interface %s";
82
568
  } else if (scope->ce_flags & ZEND_ACC_READONLY_CLASS) {
83
59
    msg = "Cannot apply #[\\AllowDynamicProperties] to readonly class %s";
84
509
  } else if (scope->ce_flags & ZEND_ACC_ENUM) {
85
24
    msg = "Cannot apply #[\\AllowDynamicProperties] to enum %s";
86
24
  }
87
661
  if (msg != NULL) {
88
176
    return zend_strpprintf(0, msg, ZSTR_VAL(scope->name));
89
176
  }
90
485
  scope->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
91
485
  return NULL;
92
661
}
93
94
static zend_string *validate_attribute(
95
  zend_attribute *attr, uint32_t target, zend_class_entry *scope)
96
314
{
97
314
  const char *msg = NULL;
98
314
  if (scope->ce_flags & ZEND_ACC_TRAIT) {
99
16
    msg = "Cannot apply #[\\Attribute] to trait %s";
100
298
  } else if (scope->ce_flags & ZEND_ACC_INTERFACE) {
101
13
    msg = "Cannot apply #[\\Attribute] to interface %s";
102
285
  } else if (scope->ce_flags & ZEND_ACC_ENUM) {
103
19
    msg = "Cannot apply #[\\Attribute] to enum %s";
104
266
  } else if (scope->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
105
13
    msg = "Cannot apply #[\\Attribute] to abstract class %s";
106
13
  }
107
314
  if (msg != NULL) {
108
61
    return zend_strpprintf(0, msg, ZSTR_VAL(scope->name));
109
61
  }
110
253
  return NULL;
111
314
}
112
113
static zend_string *validate_deprecated(
114
  zend_attribute *attr,
115
  uint32_t target,
116
  zend_class_entry *scope
117
555
) {
118
555
  if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
119
    /* Being used for a method or something, validation does not apply */
120
454
    return NULL;
121
454
  }
122
101
  if (!(scope->ce_flags & ZEND_ACC_TRAIT)) {
123
41
    const char *type = zend_get_object_type_case(scope, false);
124
41
    return zend_strpprintf(0, "Cannot apply #[\\Deprecated] to %s %s", type, ZSTR_VAL(scope->name));
125
41
  }
126
127
60
  scope->ce_flags |= ZEND_ACC_DEPRECATED;
128
60
  return NULL;
129
130
101
}
131
132
ZEND_METHOD(Attribute, __construct)
133
16
{
134
16
  zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
135
136
48
  ZEND_PARSE_PARAMETERS_START(0, 1)
137
48
    Z_PARAM_OPTIONAL
138
54
    Z_PARAM_LONG(flags)
139
16
  ZEND_PARSE_PARAMETERS_END();
140
141
16
  ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), flags);
142
16
}
143
144
ZEND_METHOD(ReturnTypeWillChange, __construct)
145
5
{
146
5
  ZEND_PARSE_PARAMETERS_NONE();
147
5
}
148
149
ZEND_METHOD(AllowDynamicProperties, __construct)
150
10
{
151
10
  ZEND_PARSE_PARAMETERS_NONE();
152
10
}
153
154
ZEND_METHOD(SensitiveParameter, __construct)
155
5
{
156
5
  ZEND_PARSE_PARAMETERS_NONE();
157
5
}
158
159
ZEND_METHOD(SensitiveParameterValue, __construct)
160
403
{
161
403
  zval *value;
162
163
1.20k
  ZEND_PARSE_PARAMETERS_START(1, 1)
164
1.59k
    Z_PARAM_ZVAL(value)
165
1.59k
  ZEND_PARSE_PARAMETERS_END();
166
167
398
  zend_update_property_ex(zend_ce_sensitive_parameter_value, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_VALUE), value);
168
398
}
169
170
ZEND_METHOD(SensitiveParameterValue, getValue)
171
48
{
172
48
  ZEND_PARSE_PARAMETERS_NONE();
173
174
48
  ZVAL_COPY(return_value, OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0));
175
48
}
176
177
ZEND_METHOD(SensitiveParameterValue, __debugInfo)
178
0
{
179
0
  ZEND_PARSE_PARAMETERS_NONE();
180
181
0
  RETURN_EMPTY_ARRAY();
182
0
}
183
184
static HashTable *attributes_sensitive_parameter_value_get_properties_for(zend_object *zobj, zend_prop_purpose purpose)
185
210
{
186
210
  return NULL;
187
210
}
188
189
ZEND_METHOD(Override, __construct)
190
5
{
191
5
  ZEND_PARSE_PARAMETERS_NONE();
192
5
}
193
194
ZEND_METHOD(Deprecated, __construct)
195
441
{
196
441
  zend_string *message = NULL;
197
441
  zend_string *since = NULL;
198
441
  zval value;
199
200
1.32k
  ZEND_PARSE_PARAMETERS_START(0, 2)
201
1.32k
    Z_PARAM_OPTIONAL
202
1.75k
    Z_PARAM_STR_OR_NULL(message)
203
1.74k
    Z_PARAM_STR_OR_NULL(since)
204
441
  ZEND_PARSE_PARAMETERS_END();
205
206
421
  if (message) {
207
334
    ZVAL_STR(&value, message);
208
334
  } else {
209
87
    ZVAL_NULL(&value);
210
87
  }
211
421
  zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value);
212
213
  /* The assignment might fail due to 'readonly'. */
214
421
  if (UNEXPECTED(EG(exception))) {
215
6
    RETURN_THROWS();
216
6
  }
217
218
415
  if (since) {
219
247
    ZVAL_STR(&value, since);
220
247
  } else {
221
168
    ZVAL_NULL(&value);
222
168
  }
223
415
  zend_update_property_ex(zend_ce_deprecated, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_SINCE), &value);
224
225
  /* The assignment might fail due to 'readonly'. */
226
415
  if (UNEXPECTED(EG(exception))) {
227
0
    RETURN_THROWS();
228
0
  }
229
415
}
230
231
static zend_string *validate_nodiscard(
232
  zend_attribute *attr, uint32_t target, zend_class_entry *scope)
233
456
{
234
456
  ZEND_ASSERT(CG(in_compilation));
235
456
  const zend_string *prop_info_name = CG(context).active_property_info_name;
236
456
  if (prop_info_name != NULL) {
237
    // Applied to a hook
238
27
    return ZSTR_INIT_LITERAL("#[\\NoDiscard] is not supported for property hooks", 0);
239
27
  }
240
429
  zend_op_array *op_array = CG(active_op_array);
241
429
  op_array->fn_flags |= ZEND_ACC_NODISCARD;
242
429
  return NULL;
243
456
}
244
245
ZEND_METHOD(NoDiscard, __construct)
246
50
{
247
50
  zend_string *message = NULL;
248
50
  zval value;
249
250
150
  ZEND_PARSE_PARAMETERS_START(0, 1)
251
150
    Z_PARAM_OPTIONAL
252
190
    Z_PARAM_STR_OR_NULL(message)
253
50
  ZEND_PARSE_PARAMETERS_END();
254
255
44
  if (message) {
256
39
    ZVAL_STR(&value, message);
257
39
  } else {
258
5
    ZVAL_NULL(&value);
259
5
  }
260
44
  zend_update_property_ex(zend_ce_nodiscard, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value);
261
262
  /* The assignment might fail due to 'readonly'. */
263
44
  if (UNEXPECTED(EG(exception))) {
264
6
    RETURN_THROWS();
265
6
  }
266
44
}
267
268
static zend_attribute *get_attribute(const HashTable *attributes, const zend_string *lcname, uint32_t offset)
269
0
{
270
0
  if (attributes) {
271
0
    zend_attribute *attr;
272
273
0
    ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
274
0
      if (attr->offset == offset && zend_string_equals(attr->lcname, lcname)) {
275
0
        return attr;
276
0
      }
277
0
    } ZEND_HASH_FOREACH_END();
278
0
  }
279
280
0
  return NULL;
281
0
}
282
283
static zend_attribute *get_attribute_str(const HashTable *attributes, const char *str, size_t len, uint32_t offset)
284
3.87M
{
285
3.87M
  if (attributes) {
286
3.01M
    zend_attribute *attr;
287
288
20.2M
    ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
289
20.2M
      if (attr->offset == offset && zend_string_equals_cstr(attr->lcname, str, len)) {
290
3.43k
        return attr;
291
3.43k
      }
292
20.2M
    } ZEND_HASH_FOREACH_END();
293
3.01M
  }
294
295
3.86M
  return NULL;
296
3.87M
}
297
298
ZEND_API zend_attribute *zend_get_attribute(const HashTable *attributes, const zend_string *lcname)
299
0
{
300
0
  return get_attribute(attributes, lcname, 0);
301
0
}
302
303
ZEND_API zend_attribute *zend_get_attribute_str(const HashTable *attributes, const char *str, size_t len)
304
2.94M
{
305
2.94M
  return get_attribute_str(attributes, str, len, 0);
306
2.94M
}
307
308
ZEND_API zend_attribute *zend_get_parameter_attribute(const HashTable *attributes, const zend_string *lcname, uint32_t offset)
309
0
{
310
0
  return get_attribute(attributes, lcname, offset + 1);
311
0
}
312
313
ZEND_API zend_attribute *zend_get_parameter_attribute_str(const HashTable *attributes, const char *str, size_t len, uint32_t offset)
314
924k
{
315
924k
  return get_attribute_str(attributes, str, len, offset + 1);
316
924k
}
317
318
ZEND_API zend_result zend_get_attribute_value(zval *ret, const zend_attribute *attr, uint32_t i, zend_class_entry *scope)
319
1.77k
{
320
1.77k
  if (i >= attr->argc) {
321
0
    return FAILURE;
322
0
  }
323
324
1.77k
  ZVAL_COPY_OR_DUP(ret, &attr->args[i].value);
325
326
1.77k
  if (Z_TYPE_P(ret) == IS_CONSTANT_AST) {
327
456
    if (SUCCESS != zval_update_constant_ex(ret, scope)) {
328
35
      zval_ptr_dtor(ret);
329
35
      return FAILURE;
330
35
    }
331
456
  }
332
333
1.73k
  return SUCCESS;
334
1.77k
}
335
336
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)
337
665
{
338
665
  zend_execute_data *call = NULL;
339
340
665
  if (filename) {
341
    /* Set up dummy call frame that makes it look like the attribute was invoked
342
     * from where it occurs in the code. */
343
217
    zend_function dummy_func;
344
217
    zend_op *opline;
345
346
217
    memset(&dummy_func, 0, sizeof(zend_function));
347
348
217
    call = zend_vm_stack_push_call_frame_ex(
349
217
      ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_execute_data), sizeof(zval)) +
350
217
      ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op), sizeof(zval)) +
351
217
      ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_function), sizeof(zval)),
352
217
      0, &dummy_func, 0, NULL);
353
354
217
    opline = (zend_op*)(call + 1);
355
217
    memset(opline, 0, sizeof(zend_op));
356
217
    opline->opcode = ZEND_DO_FCALL;
357
217
    opline->lineno = attribute_data->lineno;
358
359
217
    call->opline = opline;
360
217
    call->call = NULL;
361
217
    call->return_value = NULL;
362
217
    call->func = (zend_function*)(call->opline + 1);
363
217
    call->prev_execute_data = EG(current_execute_data);
364
365
217
    memset(call->func, 0, sizeof(zend_function));
366
217
    call->func->type = ZEND_USER_FUNCTION;
367
217
    call->func->op_array.fn_flags =
368
217
      attribute_data->flags & ZEND_ATTRIBUTE_STRICT_TYPES ? ZEND_ACC_STRICT_TYPES : 0;
369
217
    call->func->op_array.fn_flags |= ZEND_ACC_CALL_VIA_TRAMPOLINE;
370
217
    call->func->op_array.filename = filename;
371
372
217
    EG(current_execute_data) = call;
373
217
  }
374
375
665
  zval *args = NULL;
376
665
  HashTable *named_params = NULL;
377
378
665
  zend_result result = FAILURE;
379
380
665
  uint32_t argc = 0;
381
665
  if (attribute_data->argc) {
382
567
    args = emalloc(attribute_data->argc * sizeof(zval));
383
384
1.30k
    for (uint32_t i = 0; i < attribute_data->argc; i++) {
385
748
      zval val;
386
748
      if (FAILURE == zend_get_attribute_value(&val, attribute_data, i, scope)) {
387
10
        result = FAILURE;
388
10
        goto out;
389
10
      }
390
738
      if (attribute_data->args[i].name) {
391
442
        if (!named_params) {
392
286
          named_params = zend_new_array(0);
393
286
        }
394
442
        zend_hash_add_new(named_params, attribute_data->args[i].name, &val);
395
442
      } else {
396
296
        ZVAL_COPY_VALUE(&args[i], &val);
397
296
        argc++;
398
296
      }
399
738
    }
400
567
  }
401
402
655
  result = object_init_with_constructor(obj, attribute_ce, argc, args, named_params);
403
404
665
 out:
405
961
  for (uint32_t i = 0; i < argc; i++) {
406
296
    zval_ptr_dtor(&args[i]);
407
296
  }
408
409
665
  efree(args);
410
411
665
  if (named_params) {
412
286
    zend_array_destroy(named_params);
413
286
  }
414
415
665
  if (filename) {
416
217
    EG(current_execute_data) = call->prev_execute_data;
417
217
    zend_vm_stack_free_call_frame(call);
418
217
  }
419
420
665
  return result;
421
655
}
422
423
static const char *target_names[] = {
424
  "class",
425
  "function",
426
  "method",
427
  "property",
428
  "class constant",
429
  "parameter",
430
  "constant"
431
};
432
433
ZEND_API zend_string *zend_get_attribute_target_names(uint32_t flags)
434
224
{
435
224
  smart_str str = { 0 };
436
437
1.79k
  for (uint32_t i = 0; i < (sizeof(target_names) / sizeof(char *)); i++) {
438
1.56k
    if (flags & (1 << i)) {
439
273
      if (smart_str_get_len(&str)) {
440
49
        smart_str_appends(&str, ", ");
441
49
      }
442
443
273
      smart_str_appends(&str, target_names[i]);
444
273
    }
445
1.56k
  }
446
447
224
  return smart_str_extract(&str);
448
224
}
449
450
ZEND_API bool zend_is_attribute_repeated(const HashTable *attributes, const zend_attribute *attr)
451
3.93k
{
452
3.93k
  zend_attribute *other;
453
454
20.4k
  ZEND_HASH_PACKED_FOREACH_PTR(attributes, other) {
455
20.4k
    if (other != attr && other->offset == attr->offset) {
456
2.22k
      if (zend_string_equals(other->lcname, attr->lcname)) {
457
53
        return 1;
458
53
      }
459
2.22k
    }
460
20.4k
  } ZEND_HASH_FOREACH_END();
461
462
3.88k
  return 0;
463
3.93k
}
464
465
static void attr_free(zval *v)
466
709k
{
467
709k
  zend_attribute *attr = Z_PTR_P(v);
468
709k
  bool persistent = attr->flags & ZEND_ATTRIBUTE_PERSISTENT;
469
470
709k
  zend_string_release(attr->name);
471
709k
  zend_string_release(attr->lcname);
472
709k
  if (attr->validation_error != NULL) {
473
130
    zend_string_release(attr->validation_error);
474
130
  }
475
476
753k
  for (uint32_t i = 0; i < attr->argc; i++) {
477
43.8k
    if (attr->args[i].name) {
478
2.28k
      zend_string_release(attr->args[i].name);
479
2.28k
    }
480
43.8k
    if (persistent) {
481
0
      zval_internal_ptr_dtor(&attr->args[i].value);
482
43.8k
    } else {
483
43.8k
      zval_ptr_dtor(&attr->args[i].value);
484
43.8k
    }
485
43.8k
  }
486
487
709k
  pefree(attr, persistent);
488
709k
}
489
490
ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_string *name, uint32_t argc, uint32_t flags, uint32_t offset, uint32_t lineno)
491
2.08M
{
492
2.08M
  bool persistent = flags & ZEND_ATTRIBUTE_PERSISTENT;
493
2.08M
  if (*attributes == NULL) {
494
984k
    *attributes = pemalloc(sizeof(HashTable), persistent);
495
984k
    zend_hash_init(*attributes, 8, NULL, attr_free, persistent);
496
984k
  }
497
498
2.08M
  zend_attribute *attr = pemalloc(ZEND_ATTRIBUTE_SIZE(argc), persistent);
499
500
2.08M
  if (persistent == ((GC_FLAGS(name) & IS_STR_PERSISTENT) != 0)) {
501
2.08M
    attr->name = zend_string_copy(name);
502
2.08M
  } else {
503
0
    attr->name = zend_string_dup(name, persistent);
504
0
  }
505
506
2.08M
  attr->lcname = zend_string_tolower_ex(attr->name, persistent);
507
2.08M
  attr->validation_error = NULL;
508
2.08M
  attr->flags = flags;
509
2.08M
  attr->lineno = lineno;
510
2.08M
  attr->offset = offset;
511
2.08M
  attr->argc = argc;
512
513
  /* Initialize arguments to avoid partial initialization in case of fatal errors. */
514
2.16M
  for (uint32_t i = 0; i < argc; i++) {
515
81.8k
    attr->args[i].name = NULL;
516
81.8k
    ZVAL_UNDEF(&attr->args[i].value);
517
81.8k
  }
518
519
2.08M
  zend_hash_next_index_insert_ptr(*attributes, attr);
520
521
2.08M
  return attr;
522
2.08M
}
523
524
static void free_internal_attribute(zval *v)
525
0
{
526
0
  pefree(Z_PTR_P(v), 1);
527
0
}
528
529
ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce)
530
128
{
531
128
  zend_internal_attribute *internal_attr;
532
128
  zend_attribute *attr;
533
534
128
  if (ce->type != ZEND_INTERNAL_CLASS) {
535
0
    zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
536
0
  }
537
538
384
  ZEND_HASH_FOREACH_PTR(ce->attributes, attr) {
539
384
    if (zend_string_equals(attr->name, zend_ce_attribute->name)) {
540
128
      internal_attr = pemalloc(sizeof(zend_internal_attribute), 1);
541
128
      internal_attr->ce = ce;
542
128
      internal_attr->flags = Z_LVAL(attr->args[0].value);
543
128
      internal_attr->validator = NULL;
544
545
128
      zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
546
128
      zend_hash_update_ptr(&internal_attributes, lcname, internal_attr);
547
128
      zend_string_release(lcname);
548
549
128
      return internal_attr;
550
128
    }
551
384
  } ZEND_HASH_FOREACH_END();
552
553
0
  zend_error_noreturn(E_ERROR, "Classes must be first marked as attribute before being able to be registered as internal attribute class");
554
128
}
555
556
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
557
0
{
558
0
  zend_attribute *attr = zend_add_class_attribute(ce, zend_ce_attribute->name, 1);
559
0
  ZVAL_LONG(&attr->args[0].value, flags);
560
561
0
  return zend_mark_internal_attribute(ce);
562
0
}
563
564
ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname)
565
4.16M
{
566
4.16M
  return zend_hash_find_ptr(&internal_attributes, lcname);
567
4.16M
}
568
569
void zend_register_attribute_ce(void)
570
16
{
571
16
  zend_internal_attribute *attr;
572
573
16
  zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1);
574
575
16
  zend_ce_attribute = register_class_Attribute();
576
16
  attr = zend_mark_internal_attribute(zend_ce_attribute);
577
16
  attr->validator = validate_attribute;
578
579
16
  zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange();
580
16
  zend_mark_internal_attribute(zend_ce_return_type_will_change_attribute);
581
582
16
  zend_ce_allow_dynamic_properties = register_class_AllowDynamicProperties();
583
16
  attr = zend_mark_internal_attribute(zend_ce_allow_dynamic_properties);
584
16
  attr->validator = validate_allow_dynamic_properties;
585
586
16
  zend_ce_sensitive_parameter = register_class_SensitiveParameter();
587
16
  zend_mark_internal_attribute(zend_ce_sensitive_parameter);
588
589
16
  memcpy(&attributes_object_handlers_sensitive_parameter_value, &std_object_handlers, sizeof(zend_object_handlers));
590
16
  attributes_object_handlers_sensitive_parameter_value.get_properties_for = attributes_sensitive_parameter_value_get_properties_for;
591
592
  /* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */
593
16
  zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue();
594
16
  zend_ce_sensitive_parameter_value->default_object_handlers = &attributes_object_handlers_sensitive_parameter_value;
595
596
16
  zend_ce_override = register_class_Override();
597
16
  zend_mark_internal_attribute(zend_ce_override);
598
599
16
  zend_ce_deprecated = register_class_Deprecated();
600
16
  attr = zend_mark_internal_attribute(zend_ce_deprecated);
601
16
  attr->validator = validate_deprecated;
602
603
16
  zend_ce_nodiscard = register_class_NoDiscard();
604
16
  attr = zend_mark_internal_attribute(zend_ce_nodiscard);
605
16
  attr->validator = validate_nodiscard;
606
607
16
  zend_ce_delayed_target_validation = register_class_DelayedTargetValidation();
608
16
  attr = zend_mark_internal_attribute(zend_ce_delayed_target_validation);
609
16
}
610
611
void zend_attributes_shutdown(void)
612
0
{
613
0
  zend_hash_destroy(&internal_attributes);
614
0
}