Coverage Report

Created: 2022-10-14 11:19

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