Coverage Report

Created: 2026-06-13 07:01

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