Coverage Report

Created: 2026-10-28 06:20

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