Coverage Report

Created: 2022-10-06 21:30

/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_smart_str.h"
25
26
ZEND_API zend_class_entry *zend_ce_attribute;
27
28
static HashTable internal_attributes;
29
30
void validate_attribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
31
1.40k
{
32
  // TODO: More proper signature validation: Too many args, incorrect arg names.
33
1.40k
  if (attr->argc > 0) {
34
795
    zval flags;
35
36
795
    if (FAILURE == zend_get_attribute_value(&flags, attr, 0, scope)) {
37
0
      return;
38
0
    }
39
40
795
    if (Z_TYPE(flags) != IS_LONG) {
41
20
      zend_error_noreturn(E_ERROR,
42
20
        "Attribute::__construct(): Argument #1 ($flags) must must be of type int, %s given",
43
20
        zend_zval_type_name(&flags)
44
20
      );
45
20
    }
46
47
775
    if (Z_LVAL(flags) & ~ZEND_ATTRIBUTE_FLAGS) {
48
20
      zend_error_noreturn(E_ERROR, "Invalid attribute flags specified");
49
20
    }
50
51
755
    zval_ptr_dtor(&flags);
52
755
  }
53
1.40k
}
54
55
ZEND_METHOD(Attribute, __construct)
56
21
{
57
21
  zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
58
59
63
  ZEND_PARSE_PARAMETERS_START(0, 1)
60
21
    Z_PARAM_OPTIONAL
61
0
    Z_PARAM_LONG(flags)
62
21
  ZEND_PARSE_PARAMETERS_END();
63
64
21
  ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), flags);
65
21
}
66
67
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
68
0
{
69
0
  if (attributes) {
70
0
    zend_attribute *attr;
71
72
0
    ZEND_HASH_FOREACH_PTR(attributes, attr) {
73
0
      if (attr->offset == offset && zend_string_equals(attr->lcname, lcname)) {
74
0
        return attr;
75
0
      }
76
0
    } ZEND_HASH_FOREACH_END();
77
0
  }
78
79
0
  return NULL;
80
0
}
81
82
static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
83
1.21k
{
84
1.21k
  if (attributes) {
85
1.16k
    zend_attribute *attr;
86
87
3.49k
    ZEND_HASH_FOREACH_PTR(attributes, attr) {
88
1.16k
      if (attr->offset == offset && ZSTR_LEN(attr->lcname) == len) {
89
1.14k
        if (0 == memcmp(ZSTR_VAL(attr->lcname), str, len)) {
90
1.10k
          return attr;
91
1.10k
        }
92
1.14k
      }
93
1.16k
    } ZEND_HASH_FOREACH_END();
94
1.16k
  }
95
96
103
  return NULL;
97
1.21k
}
98
99
ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname)
100
0
{
101
0
  return get_attribute(attributes, lcname, 0);
102
0
}
103
104
ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len)
105
1.21k
{
106
1.21k
  return get_attribute_str(attributes, str, len, 0);
107
1.21k
}
108
109
ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
110
0
{
111
0
  return get_attribute(attributes, lcname, offset + 1);
112
0
}
113
114
ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
115
0
{
116
0
  return get_attribute_str(attributes, str, len, offset + 1);
117
0
}
118
119
ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, uint32_t i, zend_class_entry *scope)
120
6.99k
{
121
6.99k
  if (i >= attr->argc) {
122
0
    return FAILURE;
123
0
  }
124
125
6.99k
  ZVAL_COPY_OR_DUP(ret, &attr->args[i].value);
126
127
6.99k
  if (Z_TYPE_P(ret) == IS_CONSTANT_AST) {
128
3.34k
    if (SUCCESS != zval_update_constant_ex(ret, scope)) {
129
295
      zval_ptr_dtor(ret);
130
295
      return FAILURE;
131
295
    }
132
6.69k
  }
133
134
6.69k
  return SUCCESS;
135
6.69k
}
136
137
static const char *target_names[] = {
138
  "class",
139
  "function",
140
  "method",
141
  "property",
142
  "class constant",
143
  "parameter"
144
};
145
146
ZEND_API zend_string *zend_get_attribute_target_names(uint32_t flags)
147
468
{
148
468
  smart_str str = { 0 };
149
150
3.27k
  for (uint32_t i = 0; i < (sizeof(target_names) / sizeof(char *)); i++) {
151
2.80k
    if (flags & (1 << i)) {
152
621
      if (smart_str_get_len(&str)) {
153
153
        smart_str_appends(&str, ", ");
154
153
      }
155
156
621
      smart_str_appends(&str, target_names[i]);
157
621
    }
158
2.80k
  }
159
160
468
  return smart_str_extract(&str);
161
468
}
162
163
ZEND_API zend_bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr)
164
2.84k
{
165
2.84k
  zend_attribute *other;
166
167
9.18k
  ZEND_HASH_FOREACH_PTR(attributes, other) {
168
3.17k
    if (other != attr && other->offset == attr->offset) {
169
333
      if (zend_string_equals(other->lcname, attr->lcname)) {
170
266
        return 1;
171
266
      }
172
333
    }
173
3.17k
  } ZEND_HASH_FOREACH_END();
174
175
2.57k
  return 0;
176
2.84k
}
177
178
static zend_always_inline void free_attribute(zend_attribute *attr, bool persistent)
179
17.8k
{
180
17.8k
  uint32_t i;
181
182
17.8k
  zend_string_release(attr->name);
183
17.8k
  zend_string_release(attr->lcname);
184
185
28.2k
  for (i = 0; i < attr->argc; i++) {
186
10.4k
    if (attr->args[i].name) {
187
258
      zend_string_release(attr->args[i].name);
188
258
    }
189
10.4k
    zval_ptr_dtor(&attr->args[i].value);
190
10.4k
  }
191
192
17.8k
  pefree(attr, persistent);
193
17.8k
}
194
195
static void attr_free(zval *v)
196
17.8k
{
197
17.8k
  free_attribute((zend_attribute *) Z_PTR_P(v), 0);
198
17.8k
}
199
200
static void attr_pfree(zval *v)
201
0
{
202
0
  free_attribute((zend_attribute *) Z_PTR_P(v), 1);
203
0
}
204
205
ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_bool persistent, uint32_t offset, zend_string *name, uint32_t argc)
206
25.1k
{
207
25.1k
  if (*attributes == NULL) {
208
18.3k
    *attributes = pemalloc(sizeof(HashTable), persistent);
209
18.3k
    zend_hash_init(*attributes, 8, NULL, persistent ? attr_pfree : attr_free, persistent);
210
18.3k
  }
211
212
25.1k
  zend_attribute *attr = pemalloc(ZEND_ATTRIBUTE_SIZE(argc), persistent);
213
214
25.1k
  if (persistent == ((GC_FLAGS(name) & IS_STR_PERSISTENT) != 0)) {
215
24.9k
    attr->name = zend_string_copy(name);
216
168
  } else {
217
168
    attr->name = zend_string_dup(name, persistent);
218
168
  }
219
220
25.1k
  attr->lcname = zend_string_tolower_ex(attr->name, persistent);
221
25.1k
  attr->offset = offset;
222
25.1k
  attr->argc = argc;
223
224
  /* Initialize arguments to avoid partial initialization in case of fatal errors. */
225
36.0k
  for (uint32_t i = 0; i < argc; i++) {
226
10.9k
    attr->args[i].name = NULL;
227
10.9k
    ZVAL_UNDEF(&attr->args[i].value);
228
10.9k
  }
229
230
25.1k
  zend_hash_next_index_insert_ptr(*attributes, attr);
231
232
25.1k
  return attr;
233
25.1k
}
234
235
static void free_internal_attribute(zval *v)
236
0
{
237
0
  pefree(Z_PTR_P(v), 1);
238
0
}
239
240
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
241
6.83k
{
242
6.83k
  zend_internal_attribute *attr;
243
244
6.83k
  if (ce->type != ZEND_INTERNAL_CLASS) {
245
0
    zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
246
0
  }
247
248
6.83k
  attr = pemalloc(sizeof(zend_internal_attribute), 1);
249
6.83k
  attr->ce = ce;
250
6.83k
  attr->flags = flags;
251
6.83k
  attr->validator = NULL;
252
253
6.83k
  zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
254
255
6.83k
  zend_hash_update_ptr(&internal_attributes, lcname, attr);
256
6.83k
  zend_add_class_attribute(ce, zend_ce_attribute->name, 0);
257
6.83k
  zend_string_release(lcname);
258
259
6.83k
  return attr;
260
6.83k
}
261
262
ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname)
263
18.0k
{
264
18.0k
  return zend_hash_find_ptr(&internal_attributes, lcname);
265
18.0k
}
266
267
void zend_register_attribute_ce(void)
268
6.83k
{
269
6.83k
  zend_internal_attribute *attr;
270
6.83k
  zend_class_entry ce;
271
6.83k
  zend_string *str;
272
6.83k
  zval tmp;
273
274
6.83k
  zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1);
275
276
6.83k
  INIT_CLASS_ENTRY(ce, "Attribute", class_Attribute_methods);
277
6.83k
  zend_ce_attribute = zend_register_internal_class(&ce);
278
6.83k
  zend_ce_attribute->ce_flags |= ZEND_ACC_FINAL;
279
280
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS"), ZEND_ATTRIBUTE_TARGET_CLASS);
281
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_FUNCTION"), ZEND_ATTRIBUTE_TARGET_FUNCTION);
282
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_METHOD"), ZEND_ATTRIBUTE_TARGET_METHOD);
283
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PROPERTY"), ZEND_ATTRIBUTE_TARGET_PROPERTY);
284
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS_CONSTANT"), ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
285
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PARAMETER"), ZEND_ATTRIBUTE_TARGET_PARAMETER);
286
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_ALL"), ZEND_ATTRIBUTE_TARGET_ALL);
287
6.83k
  zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("IS_REPEATABLE"), ZEND_ATTRIBUTE_IS_REPEATABLE);
288
289
6.83k
  ZVAL_UNDEF(&tmp);
290
6.83k
  str = zend_string_init(ZEND_STRL("flags"), 1);
291
6.83k
  zend_declare_typed_property(zend_ce_attribute, str, &tmp, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CODE(IS_LONG, 0, 0));
292
6.83k
  zend_string_release(str);
293
294
6.83k
  attr = zend_internal_attribute_register(zend_ce_attribute, ZEND_ATTRIBUTE_TARGET_CLASS);
295
6.83k
  attr->validator = validate_attribute;
296
6.83k
}
297
298
void zend_attributes_shutdown(void)
299
0
{
300
0
  zend_hash_destroy(&internal_attributes);
301
0
}