Coverage Report

Created: 2025-12-14 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/Zend/zend_inheritance.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: Andi Gutmans <andi@php.net>                                 |
16
   |          Zeev Suraski <zeev@php.net>                                 |
17
   +----------------------------------------------------------------------+
18
*/
19
20
#include "zend.h"
21
#include "zend_API.h"
22
#include "zend_compile.h"
23
#include "zend_execute.h"
24
#include "zend_inheritance.h"
25
#include "zend_interfaces.h"
26
#include "zend_closures.h"
27
#include "zend_smart_str.h"
28
#include "zend_operators.h"
29
#include "zend_exceptions.h"
30
#include "zend_enum.h"
31
#include "zend_attributes.h"
32
#include "zend_constants.h"
33
#include "zend_observer.h"
34
35
ZEND_API zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces) = NULL;
36
ZEND_API zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies) = NULL;
37
38
/* Unresolved means that class declarations that are currently not available are needed to
39
 * determine whether the inheritance is valid or not. At runtime UNRESOLVED should be treated
40
 * as an ERROR. */
41
typedef zend_inheritance_status inheritance_status;
42
43
typedef enum {
44
  PROP_INVARIANT,
45
  PROP_COVARIANT,
46
  PROP_CONTRAVARIANT,
47
} prop_variance;
48
49
static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce);
50
static void add_compatibility_obligation(
51
    zend_class_entry *ce, const zend_function *child_fn, zend_class_entry *child_scope,
52
    const zend_function *parent_fn, zend_class_entry *parent_scope);
53
static void add_property_compatibility_obligation(
54
    zend_class_entry *ce, const zend_property_info *child_prop,
55
    const zend_property_info *parent_prop, prop_variance variance);
56
static void add_class_constant_compatibility_obligation(
57
    zend_class_entry *ce, const zend_class_constant *child_const,
58
    const zend_class_constant *parent_const, const zend_string *const_name);
59
static void add_property_hook_obligation(
60
    zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func);
61
62
static void ZEND_COLD emit_incompatible_method_error(
63
    const zend_function *child, zend_class_entry *child_scope,
64
    const zend_function *parent, zend_class_entry *parent_scope,
65
    inheritance_status status);
66
67
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent);
68
69
static void zend_type_list_copy_ctor(
70
  zend_type *const parent_type,
71
  bool use_arena,
72
  bool persistent
73
0
) {
74
0
  const zend_type_list *const old_list = ZEND_TYPE_LIST(*parent_type);
75
0
  size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
76
0
  zend_type_list *new_list = use_arena
77
0
    ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
78
79
0
  memcpy(new_list, old_list, size);
80
0
  ZEND_TYPE_SET_LIST(*parent_type, new_list);
81
0
  if (use_arena) {
82
0
    ZEND_TYPE_FULL_MASK(*parent_type) |= _ZEND_TYPE_ARENA_BIT;
83
0
  }
84
85
0
  zend_type *list_type;
86
0
  ZEND_TYPE_LIST_FOREACH_MUTABLE(new_list, list_type) {
87
0
    zend_type_copy_ctor(list_type, use_arena, persistent);
88
0
  } ZEND_TYPE_LIST_FOREACH_END();
89
0
}
90
91
0
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
92
0
  if (ZEND_TYPE_HAS_LIST(*type)) {
93
0
    zend_type_list_copy_ctor(type, use_arena, persistent);
94
0
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
95
0
    zend_string_addref(ZEND_TYPE_NAME(*type));
96
0
  }
97
0
}
98
99
static zend_function *zend_duplicate_internal_function(const zend_function *func, const zend_class_entry *ce) /* {{{ */
100
16.1k
{
101
16.1k
  zend_function *new_function;
102
103
16.1k
  if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
104
2.32k
    new_function = (zend_function *)pemalloc(sizeof(zend_internal_function), 1);
105
2.32k
    memcpy(new_function, func, sizeof(zend_internal_function));
106
13.8k
  } else {
107
13.8k
    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
108
13.8k
    memcpy(new_function, func, sizeof(zend_internal_function));
109
13.8k
    new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
110
13.8k
  }
111
16.1k
  if (EXPECTED(new_function->common.function_name)) {
112
16.1k
    zend_string_addref(new_function->common.function_name);
113
16.1k
  }
114
16.1k
  return new_function;
115
16.1k
}
116
/* }}} */
117
118
static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
119
17.2k
{
120
17.2k
  if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
121
16.1k
    return zend_duplicate_internal_function(func, ce);
122
16.1k
  } else {
123
1.05k
    if (func->op_array.refcount) {
124
1.05k
      (*func->op_array.refcount)++;
125
1.05k
    }
126
1.05k
    if (EXPECTED(func->op_array.function_name)) {
127
1.05k
      zend_string_addref(func->op_array.function_name);
128
1.05k
    }
129
1.05k
    return func;
130
1.05k
  }
131
17.2k
}
132
/* }}} */
133
134
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
135
2.22k
{
136
2.22k
  zend_class_entry *parent = ce->parent;
137
138
2.22k
  ZEND_ASSERT(parent != NULL);
139
140
  /* You cannot change create_object */
141
2.22k
  ce->create_object = parent->create_object;
142
143
  /* Inherit special functions if needed */
144
2.22k
  if (EXPECTED(!ce->get_iterator)) {
145
1.96k
    ce->get_iterator = parent->get_iterator;
146
1.96k
  }
147
2.22k
  if (EXPECTED(!ce->__get)) {
148
2.19k
    ce->__get = parent->__get;
149
2.19k
  }
150
2.22k
  if (EXPECTED(!ce->__set)) {
151
2.20k
    ce->__set = parent->__set;
152
2.20k
  }
153
2.22k
  if (EXPECTED(!ce->__unset)) {
154
2.20k
    ce->__unset = parent->__unset;
155
2.20k
  }
156
2.22k
  if (EXPECTED(!ce->__isset)) {
157
2.21k
    ce->__isset = parent->__isset;
158
2.21k
  }
159
2.22k
  if (EXPECTED(!ce->__call)) {
160
2.20k
    ce->__call = parent->__call;
161
2.20k
  }
162
2.22k
  if (EXPECTED(!ce->__callstatic)) {
163
2.20k
    ce->__callstatic = parent->__callstatic;
164
2.20k
  }
165
2.22k
  if (EXPECTED(!ce->__tostring)) {
166
2.21k
    ce->__tostring = parent->__tostring;
167
2.21k
  }
168
2.22k
  if (EXPECTED(!ce->clone)) {
169
2.21k
    ce->clone = parent->clone;
170
2.21k
  }
171
2.22k
  if (EXPECTED(!ce->__serialize)) {
172
2.22k
    ce->__serialize = parent->__serialize;
173
2.22k
  }
174
2.22k
  if (EXPECTED(!ce->__unserialize)) {
175
2.20k
    ce->__unserialize = parent->__unserialize;
176
2.20k
  }
177
2.22k
  if (EXPECTED(!ce->serialize)) {
178
2.22k
    ce->serialize = parent->serialize;
179
2.22k
  }
180
2.22k
  if (EXPECTED(!ce->unserialize)) {
181
2.22k
    ce->unserialize = parent->unserialize;
182
2.22k
  }
183
2.22k
  if (!ce->destructor) {
184
2.22k
    ce->destructor = parent->destructor;
185
2.22k
  }
186
2.22k
  if (EXPECTED(!ce->__debugInfo)) {
187
2.20k
    ce->__debugInfo = parent->__debugInfo;
188
2.20k
  }
189
190
2.22k
  if (ce->constructor) {
191
120
    if (parent->constructor && UNEXPECTED(parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) {
192
0
      zend_error_noreturn(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
193
0
        ZSTR_VAL(parent->name), ZSTR_VAL(parent->constructor->common.function_name),
194
0
        ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
195
0
    }
196
120
    return;
197
120
  }
198
199
2.10k
  ce->constructor = parent->constructor;
200
2.10k
}
201
/* }}} */
202
203
const char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
204
5
{
205
5
  if (fn_flags & ZEND_ACC_PUBLIC) {
206
2
    return "public";
207
3
  } else if (fn_flags & ZEND_ACC_PRIVATE) {
208
0
    return "private";
209
3
  } else {
210
3
    ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
211
3
    return "protected";
212
3
  }
213
5
}
214
/* }}} */
215
216
static const char *zend_asymmetric_visibility_string(uint32_t fn_flags) /* {{{ */
217
3
{
218
3
  if (fn_flags & ZEND_ACC_PRIVATE_SET) {
219
0
    return "private(set)";
220
3
  } else if (fn_flags & ZEND_ACC_PROTECTED_SET) {
221
1
    return "protected(set)";
222
2
  } else {
223
2
    ZEND_ASSERT(!(fn_flags & ZEND_ACC_PUBLIC_SET));
224
2
    return "omitted";
225
2
  }
226
3
}
227
228
355k
static zend_string *resolve_class_name(const zend_class_entry *scope, zend_string *name) {
229
355k
  ZEND_ASSERT(scope);
230
355k
  if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_PARENT)) && scope->parent) {
231
0
    if (scope->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
232
0
      return scope->parent->name;
233
0
    } else {
234
0
      return scope->parent_name;
235
0
    }
236
355k
  } else if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_SELF))) {
237
5
    return scope->name;
238
355k
  } else {
239
355k
    return name;
240
355k
  }
241
355k
}
242
243
11.4k
static bool class_visible(const zend_class_entry *ce) {
244
11.4k
  if (ce->type == ZEND_INTERNAL_CLASS) {
245
676
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
246
10.7k
  } else {
247
10.7k
    ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
248
10.7k
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
249
0
      || ce->info.user.filename == CG(compiled_filename);
250
10.7k
  }
251
11.4k
}
252
253
0
static zend_always_inline void register_unresolved_class(zend_string *name) {
254
  /* We'll autoload this class and process delayed variance obligations later. */
255
0
  if (!CG(delayed_autoloads)) {
256
0
    ALLOC_HASHTABLE(CG(delayed_autoloads));
257
0
    zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
258
0
  }
259
0
  zend_hash_add_empty_element(CG(delayed_autoloads), name);
260
0
}
261
262
static zend_class_entry *lookup_class_ex(
263
480k
    zend_class_entry *scope, zend_string *name, bool register_unresolved) {
264
480k
  zend_class_entry *ce;
265
480k
  bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
266
267
480k
  if (UNEXPECTED(!EG(active) && !in_preload)) {
268
44
    zend_string *lc_name = zend_string_tolower(name);
269
270
44
    ce = zend_hash_find_ptr(CG(class_table), lc_name);
271
272
44
    zend_string_release(lc_name);
273
274
44
    if (register_unresolved && !ce) {
275
0
      zend_error_noreturn(
276
0
        E_COMPILE_ERROR, "%s must be registered before %s",
277
0
        ZSTR_VAL(name), ZSTR_VAL(scope->name));
278
0
      }
279
280
44
    return ce;
281
44
  }
282
283
480k
  ce = zend_lookup_class_ex(
284
480k
      name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
285
286
480k
  if (!CG(in_compilation) || in_preload) {
287
0
    if (ce) {
288
0
      return ce;
289
0
    }
290
291
0
    if (register_unresolved) {
292
0
      register_unresolved_class(name);
293
0
    }
294
480k
  } else {
295
480k
    if (ce && class_visible(ce)) {
296
11.4k
      return ce;
297
11.4k
    }
298
299
    /* The current class may not be registered yet, so check for it explicitly. */
300
469k
    if (zend_string_equals_ci(scope->name, name)) {
301
1.95k
      return scope;
302
1.95k
    }
303
469k
  }
304
305
467k
  return NULL;
306
480k
}
307
308
458k
static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name) {
309
458k
  return lookup_class_ex(scope, name, /* register_unresolved */ false);
310
458k
}
311
312
/* Instanceof that's safe to use on unlinked classes. */
313
1.72k
static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) {
314
1.72k
  if (ce1 == ce2) {
315
126
    return true;
316
126
  }
317
318
1.60k
  if (ce1->ce_flags & ZEND_ACC_LINKED) {
319
1.45k
    return instanceof_function(ce1, ce2);
320
1.45k
  }
321
322
145
  if (ce1->parent) {
323
145
    zend_class_entry *parent_ce;
324
145
    if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
325
20
      parent_ce = ce1->parent;
326
125
    } else {
327
125
      parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
328
125
        ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
329
125
    }
330
331
    /* It's not sufficient to only check the parent chain itself, as need to do a full
332
     * recursive instanceof in case the parent interfaces haven't been copied yet. */
333
145
    if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
334
126
      return true;
335
126
    }
336
145
  }
337
338
19
  if (ce1->num_interfaces) {
339
0
    uint32_t i;
340
0
    if (ce1->ce_flags & ZEND_ACC_RESOLVED_INTERFACES) {
341
      /* Unlike the normal instanceof_function(), we have to perform a recursive
342
       * check here, as the parent interfaces might not have been fully copied yet. */
343
0
      for (i = 0; i < ce1->num_interfaces; i++) {
344
0
        if (unlinked_instanceof(ce1->interfaces[i], ce2)) {
345
0
          return true;
346
0
        }
347
0
      }
348
0
    } else {
349
0
      for (i = 0; i < ce1->num_interfaces; i++) {
350
0
        const zend_class_entry *ce = zend_lookup_class_ex(
351
0
          ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
352
0
          ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
353
        /* Avoid recursing if class implements itself. */
354
0
        if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
355
0
          return true;
356
0
        }
357
0
      }
358
0
    }
359
0
  }
360
361
19
  return false;
362
19
}
363
364
static bool zend_type_permits_self(
365
198
    const zend_type type, const zend_class_entry *scope, zend_class_entry *self) {
366
198
  if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
367
39
    return true;
368
39
  }
369
370
  /* Any types that may satisfy self must have already been loaded at this point
371
   * (as a parent or interface), so we never need to register delayed variance obligations
372
   * for this case. */
373
159
  const zend_type *single_type;
374
331
  ZEND_TYPE_FOREACH(type, single_type) {
375
331
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
376
158
      zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
377
158
      const zend_class_entry *ce = lookup_class(self, name);
378
158
      if (ce && unlinked_instanceof(self, ce)) {
379
115
        return true;
380
115
      }
381
158
    }
382
331
  } ZEND_TYPE_FOREACH_END();
383
44
  return false;
384
159
}
385
386
static void track_class_dependency(zend_class_entry *ce, zend_string *class_name)
387
894
{
388
894
  HashTable *ht;
389
390
894
  ZEND_ASSERT(class_name);
391
894
  if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
392
894
    return;
393
894
  } else if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_SELF))
394
0
          || zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_PARENT))) {
395
0
    return;
396
0
  }
397
398
0
#ifndef ZEND_WIN32
399
  /* On non-Windows systems, internal classes are always the same,
400
   * so there is no need to explicitly track them. */
401
0
  if (ce->type == ZEND_INTERNAL_CLASS) {
402
0
    return;
403
0
  }
404
0
#endif
405
406
0
  ht = (HashTable*)CG(current_linking_class)->inheritance_cache;
407
408
0
  if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
409
    // TODO: dependency on not-immutable class ???
410
0
    if (ht) {
411
0
      zend_hash_destroy(ht);
412
0
      FREE_HASHTABLE(ht);
413
0
      CG(current_linking_class)->inheritance_cache = NULL;
414
0
    }
415
0
    CG(current_linking_class)->ce_flags &= ~ZEND_ACC_CACHEABLE;
416
0
    CG(current_linking_class) = NULL;
417
0
    return;
418
0
  }
419
420
  /* Record dependency */
421
0
  if (!ht) {
422
0
    ALLOC_HASHTABLE(ht);
423
0
    zend_hash_init(ht, 0, NULL, NULL, 0);
424
0
    CG(current_linking_class)->inheritance_cache = (zend_inheritance_cache_entry*)ht;
425
0
  }
426
0
  zend_hash_add_ptr(ht, class_name, ce);
427
0
}
428
429
/* Check whether any type in the fe_type intersection type is a subtype of the proto class. */
430
static inheritance_status zend_is_intersection_subtype_of_class(
431
    zend_class_entry *fe_scope, const zend_type fe_type,
432
    zend_class_entry *proto_scope, zend_string *proto_class_name, zend_class_entry *proto_ce)
433
73.7k
{
434
73.7k
  ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(fe_type));
435
73.7k
  bool have_unresolved = false;
436
73.7k
  const zend_type *single_type;
437
438
  /* Traverse the list of child types and check that at least one is
439
   * a subtype of the parent type being checked */
440
296k
  ZEND_TYPE_FOREACH(fe_type, single_type) {
441
296k
    zend_class_entry *fe_ce;
442
296k
    zend_string *fe_class_name = NULL;
443
296k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
444
222k
      fe_class_name =
445
222k
        resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
446
222k
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
447
21.5k
        return INHERITANCE_SUCCESS;
448
21.5k
      }
449
450
200k
      if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
451
200k
      fe_ce = lookup_class(fe_scope, fe_class_name);
452
200k
    } else {
453
      /* standard type in an intersection type is impossible,
454
       * because it would be a fatal compile error */
455
0
      ZEND_UNREACHABLE();
456
0
      continue;
457
0
    }
458
459
200k
    if (!fe_ce || !proto_ce) {
460
200k
      have_unresolved = true;
461
200k
      continue;
462
200k
    }
463
336
    if (unlinked_instanceof(fe_ce, proto_ce)) {
464
41
      track_class_dependency(fe_ce, fe_class_name);
465
41
      track_class_dependency(proto_ce, proto_class_name);
466
41
      return INHERITANCE_SUCCESS;
467
41
    }
468
336
  } ZEND_TYPE_FOREACH_END();
469
470
52.1k
  return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
471
73.7k
}
472
473
/* Check whether a single class proto type is a subtype of a potentially complex fe_type. */
474
static inheritance_status zend_is_class_subtype_of_type(
475
    zend_class_entry *fe_scope, zend_string *fe_class_name,
476
13.2k
    zend_class_entry *proto_scope, const zend_type proto_type) {
477
13.2k
  zend_class_entry *fe_ce = NULL;
478
13.2k
  bool have_unresolved = false;
479
480
  /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
481
13.2k
  if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_OBJECT) {
482
    /* Currently, any class name would be allowed here. We still perform a class lookup
483
     * for forward-compatibility reasons, as we may have named types in the future that
484
     * are not classes (such as typedefs). */
485
350
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
486
350
    if (!fe_ce) {
487
147
      have_unresolved = true;
488
203
    } else {
489
203
      track_class_dependency(fe_ce, fe_class_name);
490
203
      return INHERITANCE_SUCCESS;
491
203
    }
492
350
  }
493
494
  /* If the parent has 'callable' as a return type, then Closure satisfies the co-variant check */
495
13.0k
  if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_CALLABLE) {
496
91
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
497
91
    if (!fe_ce) {
498
38
      have_unresolved = true;
499
53
    } else if (fe_ce == zend_ce_closure) {
500
44
      track_class_dependency(fe_ce, fe_class_name);
501
44
      return INHERITANCE_SUCCESS;
502
44
    }
503
91
  }
504
505
  /* If the parent has 'static' as a return type, then final classes could replace it with self */
506
13.0k
  if ((ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_STATIC) && (fe_scope->ce_flags & ZEND_ACC_FINAL)) {
507
0
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
508
0
    if (!fe_ce) {
509
0
      have_unresolved = true;
510
0
    } else if (fe_ce == fe_scope) {
511
0
      track_class_dependency(fe_ce, fe_class_name);
512
0
      return INHERITANCE_SUCCESS;
513
0
    }
514
0
  }
515
516
13.0k
  const zend_type *single_type;
517
518
  /* Traverse the list of parent types and check if the current child (FE)
519
   * class is the subtype of at least one of them (union) or all of them (intersection). */
520
13.0k
  bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
521
53.5k
  ZEND_TYPE_FOREACH(proto_type, single_type) {
522
53.5k
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
523
7.92k
      inheritance_status subtype_status = zend_is_class_subtype_of_type(
524
7.92k
        fe_scope, fe_class_name, proto_scope, *single_type);
525
526
7.92k
      switch (subtype_status) {
527
211
        case INHERITANCE_ERROR:
528
211
          if (is_intersection) {
529
0
            return INHERITANCE_ERROR;
530
0
          }
531
211
          continue;
532
7.55k
        case INHERITANCE_UNRESOLVED:
533
7.55k
          have_unresolved = true;
534
7.55k
          continue;
535
162
        case INHERITANCE_SUCCESS:
536
162
          if (!is_intersection) {
537
162
            return INHERITANCE_SUCCESS;
538
162
          }
539
0
          continue;
540
0
        EMPTY_SWITCH_DEFAULT_CASE();
541
7.92k
      }
542
7.92k
    }
543
544
32.5k
    zend_class_entry *proto_ce;
545
32.5k
    zend_string *proto_class_name = NULL;
546
32.5k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
547
32.1k
      proto_class_name =
548
32.1k
        resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
549
32.1k
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
550
1.90k
        if (!is_intersection) {
551
1.68k
          return INHERITANCE_SUCCESS;
552
1.68k
        }
553
218
        continue;
554
1.90k
      }
555
556
30.2k
      if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
557
30.2k
      proto_ce = lookup_class(proto_scope, proto_class_name);
558
30.2k
    } else {
559
      /* standard type */
560
389
      ZEND_ASSERT(!is_intersection);
561
389
      continue;
562
389
    }
563
564
30.2k
    if (!fe_ce || !proto_ce) {
565
29.1k
      have_unresolved = true;
566
29.1k
      continue;
567
29.1k
    }
568
1.12k
    if (unlinked_instanceof(fe_ce, proto_ce)) {
569
277
      track_class_dependency(fe_ce, fe_class_name);
570
277
      track_class_dependency(proto_ce, proto_class_name);
571
277
      if (!is_intersection) {
572
105
        return INHERITANCE_SUCCESS;
573
105
      }
574
850
    } else {
575
850
      if (is_intersection) {
576
211
        return INHERITANCE_ERROR;
577
211
      }
578
850
    }
579
1.12k
  } ZEND_TYPE_FOREACH_END();
580
581
10.8k
  if (have_unresolved) {
582
10.4k
    return INHERITANCE_UNRESOLVED;
583
10.4k
  }
584
462
  return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
585
10.8k
}
586
587
81.9k
static zend_string *get_class_from_type(const zend_class_entry *scope, const zend_type single_type) {
588
81.9k
  if (ZEND_TYPE_HAS_NAME(single_type)) {
589
79.1k
    return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
590
79.1k
  }
591
2.83k
  return NULL;
592
81.9k
}
593
594
9.43k
static void register_unresolved_classes(zend_class_entry *scope, const zend_type type) {
595
9.43k
  const zend_type *single_type;
596
37.0k
  ZEND_TYPE_FOREACH(type, single_type) {
597
37.0k
    if (ZEND_TYPE_HAS_LIST(*single_type)) {
598
5.36k
      register_unresolved_classes(scope, *single_type);
599
5.36k
      continue;
600
5.36k
    }
601
22.2k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
602
22.1k
      zend_string *class_name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
603
22.1k
      lookup_class_ex(scope, class_name, /* register_unresolved */ true);
604
22.1k
    }
605
22.2k
  } ZEND_TYPE_FOREACH_END();
606
9.43k
}
607
608
static inheritance_status zend_is_intersection_subtype_of_type(
609
  zend_class_entry *fe_scope, const zend_type fe_type,
610
  zend_class_entry *proto_scope, const zend_type proto_type)
611
23.1k
{
612
23.1k
  bool have_unresolved = false;
613
23.1k
  const zend_type *single_type;
614
23.1k
  uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
615
616
  /* Currently, for object type any class name would be allowed here.
617
   * We still perform a class lookup for forward-compatibility reasons,
618
   * as we may have named types in the future that are not classes
619
   * (such as typedefs). */
620
23.1k
  if (proto_type_mask & MAY_BE_OBJECT) {
621
63
    ZEND_TYPE_FOREACH(fe_type, single_type) {
622
63
      zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
623
63
      if (!fe_class_name) {
624
0
        continue;
625
0
      }
626
42
      zend_class_entry *fe_ce = lookup_class(fe_scope, fe_class_name);
627
42
      if (fe_ce) {
628
11
        track_class_dependency(fe_ce, fe_class_name);
629
11
        return INHERITANCE_SUCCESS;
630
31
      } else {
631
31
        have_unresolved = true;
632
31
      }
633
42
    } ZEND_TYPE_FOREACH_END();
634
21
  }
635
636
  /* U_1&...&U_n < V_1&...&V_m if forall V_j. exists U_i. U_i < V_j.
637
   * U_1&...&U_n < V_1|...|V_m if exists V_j. exists U_i. U_i < V_j.
638
   * As such, we need to iterate over proto_type (V_j) first and use a different
639
   * quantifier depending on whether fe_type is a union or an intersection. */
640
23.1k
  inheritance_status early_exit_status =
641
23.1k
    ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
642
116k
  ZEND_TYPE_FOREACH(proto_type, single_type) {
643
116k
    inheritance_status status;
644
645
116k
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
646
19.4k
      status = zend_is_intersection_subtype_of_type(
647
19.4k
        fe_scope, fe_type, proto_scope, *single_type);
648
74.0k
    } else {
649
74.0k
      zend_string *proto_class_name = get_class_from_type(proto_scope, *single_type);
650
74.0k
      if (!proto_class_name) {
651
331
        continue;
652
331
      }
653
654
73.7k
      zend_class_entry *proto_ce = NULL;
655
73.7k
      status = zend_is_intersection_subtype_of_class(
656
73.7k
        fe_scope, fe_type, proto_scope, proto_class_name, proto_ce);
657
73.7k
    }
658
659
93.1k
    if (status == early_exit_status) {
660
813
      return status;
661
813
    }
662
92.3k
    if (status == INHERITANCE_UNRESOLVED) {
663
70.9k
      have_unresolved = true;
664
70.9k
    }
665
92.3k
  } ZEND_TYPE_FOREACH_END();
666
667
22.2k
  if (have_unresolved) {
668
21.3k
    return INHERITANCE_UNRESOLVED;
669
21.3k
  }
670
671
985
  return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
672
22.2k
}
673
674
ZEND_API inheritance_status zend_perform_covariant_type_check(
675
    zend_class_entry *fe_scope, const zend_type fe_type,
676
    zend_class_entry *proto_scope, const zend_type proto_type)
677
7.72k
{
678
7.72k
  ZEND_ASSERT(ZEND_TYPE_IS_SET(fe_type) && ZEND_TYPE_IS_SET(proto_type));
679
680
  /* Apart from void, everything is trivially covariant to the mixed type.
681
   * Handle this case separately to ensure it never requires class loading. */
682
7.72k
  if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
683
228
      !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
684
226
    return INHERITANCE_SUCCESS;
685
226
  }
686
687
  /* Builtin types may be removed, but not added */
688
7.50k
  uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
689
7.50k
  uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
690
7.50k
  uint32_t added_types = fe_type_mask & ~proto_type_mask;
691
7.50k
  if (added_types) {
692
872
    if ((added_types & MAY_BE_STATIC)
693
198
        && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
694
      /* Replacing type that accepts self with static is okay */
695
154
      added_types &= ~MAY_BE_STATIC;
696
154
    }
697
698
872
    if (added_types == MAY_BE_NEVER) {
699
      /* never is the bottom type */
700
4
      return INHERITANCE_SUCCESS;
701
4
    }
702
703
868
    if (added_types) {
704
      /* Otherwise adding new types is illegal */
705
714
      return INHERITANCE_ERROR;
706
714
    }
707
868
  }
708
709
6.78k
  inheritance_status early_exit_status;
710
6.78k
  bool have_unresolved = false;
711
712
6.78k
  if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
713
499
    early_exit_status =
714
499
      ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
715
499
    inheritance_status status = zend_is_intersection_subtype_of_type(
716
499
      fe_scope, fe_type, proto_scope, proto_type);
717
718
499
    if (status == early_exit_status) {
719
23
      return status;
720
23
    }
721
476
    if (status == INHERITANCE_UNRESOLVED) {
722
85
      have_unresolved = true;
723
85
    }
724
6.28k
  } else {
725
    /* U_1|...|U_n < V_1|...|V_m if forall U_i. exists V_j. U_i < V_j.
726
     * U_1|...|U_n < V_1&...&V_m if forall U_i. forall V_j. U_i < V_j.
727
     * We need to iterate over fe_type (U_i) first and the logic is independent of
728
     * whether proto_type is a union or intersection (only the inner check differs). */
729
6.28k
    early_exit_status = INHERITANCE_ERROR;
730
6.28k
    const zend_type *single_type;
731
17.3k
    ZEND_TYPE_FOREACH(fe_type, single_type) {
732
17.3k
      inheritance_status status;
733
      /* Union has an intersection type as it's member */
734
17.3k
      if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
735
3.18k
        status = zend_is_intersection_subtype_of_type(
736
3.18k
          fe_scope, *single_type, proto_scope, proto_type);
737
7.86k
      } else {
738
7.86k
        zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
739
7.86k
        if (!fe_class_name) {
740
2.50k
          continue;
741
2.50k
        }
742
743
5.36k
        status = zend_is_class_subtype_of_type(
744
5.36k
          fe_scope, fe_class_name, proto_scope, proto_type);
745
5.36k
      }
746
747
8.54k
      if (status == early_exit_status) {
748
291
        return status;
749
291
      }
750
8.25k
      if (status == INHERITANCE_UNRESOLVED) {
751
5.24k
        have_unresolved = true;
752
5.24k
      }
753
8.25k
    } ZEND_TYPE_FOREACH_END();
754
6.28k
  }
755
756
6.47k
  if (!have_unresolved) {
757
4.43k
    return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
758
4.43k
  }
759
760
2.03k
  register_unresolved_classes(fe_scope, fe_type);
761
2.03k
  register_unresolved_classes(proto_scope, proto_type);
762
2.03k
  return INHERITANCE_UNRESOLVED;
763
6.47k
}
764
765
static inheritance_status zend_do_perform_arg_type_hint_check(
766
    zend_class_entry *fe_scope, zend_arg_info *fe_arg_info,
767
    zend_class_entry *proto_scope, zend_arg_info *proto_arg_info) /* {{{ */
768
2.15k
{
769
2.15k
  if (!ZEND_TYPE_IS_SET(fe_arg_info->type) || ZEND_TYPE_PURE_MASK(fe_arg_info->type) == MAY_BE_ANY) {
770
    /* Child with no type or mixed type is always compatible */
771
253
    return INHERITANCE_SUCCESS;
772
253
  }
773
774
1.90k
  if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
775
    /* Child defines a type, but parent doesn't, violates LSP */
776
13
    return INHERITANCE_ERROR;
777
13
  }
778
779
  /* Contravariant type check is performed as a covariant type check with swapped
780
   * argument order. */
781
1.89k
  return zend_perform_covariant_type_check(
782
1.89k
    proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
783
1.90k
}
784
/* }}} */
785
786
/* For trait methods, fe_scope/proto_scope may differ from fe/proto->common.scope,
787
 * as self will refer to the self of the class the trait is used in, not the trait
788
 * the method was declared in. */
789
static inheritance_status zend_do_perform_implementation_check(
790
    const zend_function *fe, zend_class_entry *fe_scope,
791
    const zend_function *proto, zend_class_entry *proto_scope) /* {{{ */
792
3.27k
{
793
3.27k
  uint32_t num_args, proto_num_args, fe_num_args;
794
3.27k
  inheritance_status status, local_status;
795
3.27k
  bool proto_is_variadic, fe_is_variadic;
796
797
  /* Checks for constructors only if they are declared in an interface,
798
   * or explicitly marked as abstract
799
   */
800
3.27k
  ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
801
3.27k
    && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
802
3.27k
      && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)));
803
804
  /* If the prototype method is private and not abstract, we do not enforce a signature.
805
   * private abstract methods can only occur in traits. */
806
3.27k
  ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
807
3.27k
      || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
808
809
  /* The number of required arguments cannot increase. */
810
3.27k
  if (proto->common.required_num_args < fe->common.required_num_args) {
811
46
    return INHERITANCE_ERROR;
812
46
  }
813
814
  /* by-ref constraints on return values are covariant */
815
3.23k
  if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
816
110
    && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
817
91
    return INHERITANCE_ERROR;
818
91
  }
819
820
3.14k
  proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
821
3.14k
  fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
822
823
  /* A variadic function cannot become non-variadic */
824
3.14k
  if (proto_is_variadic && !fe_is_variadic) {
825
0
    return INHERITANCE_ERROR;
826
0
  }
827
828
  /* The variadic argument is not included in the stored argument count. */
829
3.14k
  proto_num_args = proto->common.num_args + proto_is_variadic;
830
3.14k
  fe_num_args = fe->common.num_args + fe_is_variadic;
831
3.14k
  num_args = MAX(proto_num_args, fe_num_args);
832
833
3.14k
  status = INHERITANCE_SUCCESS;
834
5.86k
  for (uint32_t i = 0; i < num_args; i++) {
835
2.98k
    zend_arg_info *proto_arg_info =
836
2.98k
      i < proto_num_args ? &proto->common.arg_info[i] :
837
2.98k
      proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
838
2.98k
    zend_arg_info *fe_arg_info =
839
2.98k
      i < fe_num_args ? &fe->common.arg_info[i] :
840
2.98k
      fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
841
2.98k
    if (!proto_arg_info) {
842
      /* A new (optional) argument has been added, which is fine. */
843
736
      continue;
844
736
    }
845
2.24k
    if (!fe_arg_info) {
846
      /* An argument has been removed. This is considered illegal, because arity checks
847
       * work based on a model where passing more than the declared number of parameters
848
       * to a function is an error. */
849
88
      return INHERITANCE_ERROR;
850
88
    }
851
852
2.15k
    local_status = zend_do_perform_arg_type_hint_check(
853
2.15k
      fe_scope, fe_arg_info, proto_scope, proto_arg_info);
854
855
2.15k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
856
575
      if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
857
144
        return INHERITANCE_ERROR;
858
144
      }
859
431
      ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
860
431
      status = INHERITANCE_UNRESOLVED;
861
431
    }
862
863
    /* by-ref constraints on arguments are invariant */
864
2.01k
    if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
865
25
      return INHERITANCE_ERROR;
866
25
    }
867
2.01k
  }
868
869
  /* Check return type compatibility, but only if the prototype already specifies
870
   * a return type. Adding a new return type is always valid. */
871
2.88k
  if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
872
    /* Removing a return type is not valid, unless the parent return type is tentative. */
873
2.49k
    if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
874
408
      if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
875
203
        return INHERITANCE_ERROR;
876
203
      }
877
205
      if (status == INHERITANCE_SUCCESS) {
878
205
        return INHERITANCE_WARNING;
879
205
      }
880
0
      return status;
881
205
    }
882
883
2.09k
    local_status = zend_perform_covariant_type_check(
884
2.09k
      fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
885
886
2.09k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
887
808
      if (local_status == INHERITANCE_ERROR
888
617
          && ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
889
479
        local_status = INHERITANCE_WARNING;
890
479
      }
891
808
      return local_status;
892
808
    }
893
2.09k
  }
894
895
1.66k
  return status;
896
2.88k
}
897
/* }}} */
898
899
static ZEND_COLD void zend_append_type_hint(
900
    smart_str *str, zend_class_entry *scope, const zend_arg_info *arg_info, bool return_hint) /* {{{ */
901
3.14k
{
902
3.14k
  if (ZEND_TYPE_IS_SET(arg_info->type)) {
903
2.78k
    zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
904
2.78k
    smart_str_append(str, type_str);
905
2.78k
    zend_string_release(type_str);
906
2.78k
    if (!return_hint) {
907
1.90k
      smart_str_appendc(str, ' ');
908
1.90k
    }
909
2.78k
  }
910
3.14k
}
911
/* }}} */
912
913
static ZEND_COLD zend_string *zend_get_function_declaration(
914
    const zend_function *fptr, zend_class_entry *scope) /* {{{ */
915
1.21k
{
916
1.21k
  smart_str str = {0};
917
918
1.21k
  if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
919
400
    smart_str_appendc(&str, '&');
920
400
  }
921
922
1.21k
  if (fptr->common.scope) {
923
1.21k
    if (fptr->common.scope->ce_flags & ZEND_ACC_ANON_CLASS) {
924
      /* cut off on NULL byte ... class@anonymous */
925
0
      smart_str_appends(&str, ZSTR_VAL(fptr->common.scope->name));
926
1.21k
    } else {
927
1.21k
      smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), ZSTR_LEN(fptr->common.scope->name));
928
1.21k
    }
929
1.21k
    smart_str_appends(&str, "::");
930
1.21k
  }
931
932
1.21k
  smart_str_append(&str, fptr->common.function_name);
933
1.21k
  smart_str_appendc(&str, '(');
934
935
1.21k
  if (fptr->common.arg_info) {
936
1.11k
    uint32_t num_args, required;
937
1.11k
    zend_arg_info *arg_info = fptr->common.arg_info;
938
939
1.11k
    required = fptr->common.required_num_args;
940
1.11k
    num_args = fptr->common.num_args;
941
1.11k
    if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
942
2
      num_args++;
943
2
    }
944
3.38k
    for (uint32_t i = 0; i < num_args;) {
945
2.26k
      zend_append_type_hint(&str, scope, arg_info, false);
946
947
2.26k
      if (ZEND_ARG_SEND_MODE(arg_info)) {
948
51
        smart_str_appendc(&str, '&');
949
51
      }
950
951
2.26k
      if (ZEND_ARG_IS_VARIADIC(arg_info)) {
952
2
        smart_str_appends(&str, "...");
953
2
      }
954
955
2.26k
      smart_str_appendc(&str, '$');
956
2.26k
      if (fptr->type == ZEND_INTERNAL_FUNCTION) {
957
684
        smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
958
1.58k
      } else {
959
1.58k
        smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name));
960
1.58k
      }
961
962
2.26k
      if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
963
1.74k
        smart_str_appends(&str, " = ");
964
965
1.74k
        if (fptr->type == ZEND_INTERNAL_FUNCTION) {
966
603
          if (((zend_internal_arg_info*)arg_info)->default_value) {
967
603
            smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->default_value);
968
603
          } else {
969
0
            smart_str_appends(&str, "<default>");
970
0
          }
971
1.13k
        } else {
972
1.13k
          zend_op *precv = NULL;
973
1.13k
          {
974
1.13k
            uint32_t idx  = i;
975
1.13k
            zend_op *op = fptr->op_array.opcodes;
976
1.13k
            const zend_op *end = op + fptr->op_array.last;
977
978
1.13k
            ++idx;
979
7.73k
            while (op < end) {
980
6.60k
              if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
981
4.54k
                  && op->op1.num == (zend_ulong)idx)
982
1.13k
              {
983
1.13k
                precv = op;
984
1.13k
              }
985
6.60k
              ++op;
986
6.60k
            }
987
1.13k
          }
988
1.13k
          if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
989
1.13k
            zval *zv = RT_CONSTANT(precv, precv->op2);
990
991
1.13k
            if (Z_TYPE_P(zv) == IS_FALSE) {
992
11
              smart_str_appends(&str, "false");
993
1.12k
            } else if (Z_TYPE_P(zv) == IS_TRUE) {
994
7
              smart_str_appends(&str, "true");
995
1.12k
            } else if (Z_TYPE_P(zv) == IS_NULL) {
996
10
              smart_str_appends(&str, "null");
997
1.11k
            } else if (Z_TYPE_P(zv) == IS_STRING) {
998
32
              smart_str_appendc(&str, '\'');
999
32
              smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
1000
32
              if (Z_STRLEN_P(zv) > 10) {
1001
6
                smart_str_appends(&str, "...");
1002
6
              }
1003
32
              smart_str_appendc(&str, '\'');
1004
1.07k
            } else if (Z_TYPE_P(zv) == IS_ARRAY) {
1005
3
              if (zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0) {
1006
2
                smart_str_appends(&str, "[]");
1007
2
              } else {
1008
1
                smart_str_appends(&str, "[...]");
1009
1
              }
1010
1.07k
            } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
1011
1.02k
              zend_ast *ast = Z_ASTVAL_P(zv);
1012
1.02k
              if (ast->kind == ZEND_AST_CONSTANT) {
1013
390
                smart_str_append(&str, zend_ast_get_constant_name(ast));
1014
630
              } else if (ast->kind == ZEND_AST_CLASS_CONST
1015
13
               && ast->child[1]->kind == ZEND_AST_ZVAL
1016
11
               && Z_TYPE_P(zend_ast_get_zval(ast->child[1])) == IS_STRING) {
1017
11
                smart_str_append(&str, zend_ast_get_str(ast->child[0]));
1018
11
                smart_str_appends(&str, "::");
1019
11
                smart_str_append(&str, zend_ast_get_str(ast->child[1]));
1020
619
              } else {
1021
619
                smart_str_appends(&str, "<expression>");
1022
619
              }
1023
1.02k
            } else {
1024
55
              zend_string *tmp_zv_str;
1025
55
              zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str);
1026
55
              smart_str_append(&str, zv_str);
1027
55
              zend_tmp_string_release(tmp_zv_str);
1028
55
            }
1029
1.13k
          }
1030
1.13k
        }
1031
1.74k
      }
1032
1033
2.26k
      if (++i < num_args) {
1034
1.29k
        smart_str_appends(&str, ", ");
1035
1.29k
      }
1036
2.26k
      arg_info++;
1037
2.26k
    }
1038
1.11k
  }
1039
1040
1.21k
  smart_str_appendc(&str, ')');
1041
1042
1.21k
  if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1043
877
    smart_str_appends(&str, ": ");
1044
877
    zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, true);
1045
877
  }
1046
1.21k
  smart_str_0(&str);
1047
1048
1.21k
  return str.s;
1049
1.21k
}
1050
/* }}} */
1051
1052
614
static zend_always_inline zend_string *func_filename(const zend_function *fn) {
1053
614
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
1054
614
}
1055
1056
614
static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
1057
614
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
1058
614
}
1059
1060
static void ZEND_COLD emit_incompatible_method_error(
1061
    const zend_function *child, zend_class_entry *child_scope,
1062
    const zend_function *parent, zend_class_entry *parent_scope,
1063
608
    inheritance_status status) {
1064
608
  zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
1065
608
  zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
1066
608
  if (status == INHERITANCE_UNRESOLVED) {
1067
    // TODO Improve error message if first unresolved class is present in child and parent?
1068
    /* Fetch the first unresolved class from registered autoloads */
1069
0
    const zend_string *unresolved_class = NULL;
1070
0
    ZEND_HASH_MAP_FOREACH_STR_KEY(CG(delayed_autoloads), unresolved_class) {
1071
0
      break;
1072
0
    } ZEND_HASH_FOREACH_END();
1073
0
    ZEND_ASSERT(unresolved_class);
1074
1075
0
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1076
0
      "Could not check compatibility between %s and %s, because class %s is not available",
1077
0
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
1078
608
  } else if (status == INHERITANCE_WARNING) {
1079
314
    const zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
1080
314
      child->common.attributes,
1081
314
      "returntypewillchange",
1082
314
      sizeof("returntypewillchange")-1
1083
314
    );
1084
1085
314
    if (!return_type_will_change_attribute) {
1086
313
      zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1087
313
        "Return type of %s should either be compatible with %s, "
1088
313
        "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1089
313
        ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1090
313
      ZEND_ASSERT(!EG(exception));
1091
313
    }
1092
314
  } else {
1093
294
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1094
294
      "Declaration of %s must be compatible with %s",
1095
294
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1096
294
  }
1097
608
  zend_string_efree(child_prototype);
1098
608
  zend_string_efree(parent_prototype);
1099
608
}
1100
1101
static void perform_delayable_implementation_check(
1102
    zend_class_entry *ce,
1103
    const zend_function *fe, zend_class_entry *fe_scope,
1104
    const zend_function *proto, zend_class_entry *proto_scope)
1105
1.50k
{
1106
1.50k
  inheritance_status status =
1107
1.50k
    zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1108
1.50k
  if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
1109
609
    if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
1110
1
      add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1111
608
    } else {
1112
608
      ZEND_ASSERT(status == INHERITANCE_ERROR || status == INHERITANCE_WARNING);
1113
608
      emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1114
608
    }
1115
609
  }
1116
1.50k
}
1117
1118
3.31k
#define ZEND_INHERITANCE_LAZY_CHILD_CLONE     (1<<0)
1119
5.34k
#define ZEND_INHERITANCE_CHECK_SILENT         (1<<1) /* don't throw errors */
1120
18.0k
#define ZEND_INHERITANCE_CHECK_PROTO          (1<<2) /* check method prototype (it might be already checked before) */
1121
6.85k
#define ZEND_INHERITANCE_CHECK_VISIBILITY     (1<<3)
1122
5.72k
#define ZEND_INHERITANCE_SET_CHILD_CHANGED    (1<<4)
1123
5.69k
#define ZEND_INHERITANCE_SET_CHILD_PROTO      (1<<5)
1124
3.93k
#define ZEND_INHERITANCE_RESET_CHILD_OVERRIDE (1<<6)
1125
1126
static inheritance_status do_inheritance_check_on_method(
1127
    zend_function *child, zend_class_entry *child_scope,
1128
    zend_function *parent, zend_class_entry *parent_scope,
1129
    zend_class_entry *ce, zval *child_zv, uint32_t flags) /* {{{ */
1130
3.88k
{
1131
3.88k
  uint32_t child_flags;
1132
3.88k
  uint32_t parent_flags = parent->common.fn_flags;
1133
3.88k
  zend_function *proto;
1134
1135
3.88k
#define SEPARATE_METHOD() do { \
1136
1.52k
      if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1137
1.52k
       && child_scope != ce \
1138
       /* Trait methods have already been separated at this point. However, their */ \
1139
       /* scope isn't fixed until after inheritance checks to preserve the scope */ \
1140
       /* in error messages. Skip them here explicitly. */ \
1141
1.52k
       && !(child_scope->ce_flags & ZEND_ACC_TRAIT) \
1142
1.52k
       && child->type == ZEND_USER_FUNCTION) { \
1143
        /* op_array wasn't duplicated yet */ \
1144
0
        zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); \
1145
0
        memcpy(new_function, child, sizeof(zend_op_array)); \
1146
0
        Z_PTR_P(child_zv) = child = new_function; \
1147
0
        flags &= ~ZEND_INHERITANCE_LAZY_CHILD_CLONE; \
1148
0
      } \
1149
1.52k
    } while(0)
1150
1151
3.88k
  if (UNEXPECTED((parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_ABSTRACT|ZEND_ACC_CTOR)) == ZEND_ACC_PRIVATE)) {
1152
121
    if (flags & ZEND_INHERITANCE_SET_CHILD_CHANGED) {
1153
18
      SEPARATE_METHOD();
1154
18
      child->common.fn_flags |= ZEND_ACC_CHANGED;
1155
18
    }
1156
    /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
1157
121
    return INHERITANCE_SUCCESS;
1158
121
  }
1159
1160
3.76k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO) && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
1161
11
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1162
10
      return INHERITANCE_ERROR;
1163
10
    }
1164
1
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1165
1
      "Cannot override final method %s::%s()",
1166
1
      ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
1167
11
  }
1168
1169
3.75k
  child_flags = child->common.fn_flags;
1170
  /* You cannot change from static to non static and vice versa.
1171
   */
1172
3.75k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1173
3.42k
   && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
1174
73
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1175
70
      return INHERITANCE_ERROR;
1176
70
    }
1177
3
    if (child_flags & ZEND_ACC_STATIC) {
1178
1
      zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1179
1
        "Cannot make non static method %s::%s() static in class %s",
1180
1
        ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1181
2
    } else {
1182
2
      zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1183
2
        "Cannot make static method %s::%s() non static in class %s",
1184
2
        ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1185
2
    }
1186
3
  }
1187
1188
  /* Disallow making an inherited method abstract. */
1189
3.68k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1190
3.35k
   && UNEXPECTED((child_flags & ZEND_ACC_ABSTRACT) > (parent_flags & ZEND_ACC_ABSTRACT))) {
1191
0
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1192
0
      return INHERITANCE_ERROR;
1193
0
    }
1194
0
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1195
0
      "Cannot make non abstract method %s::%s() abstract in class %s",
1196
0
      ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1197
0
  }
1198
1199
3.68k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_CHANGED)
1200
1.40k
   && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
1201
6
    SEPARATE_METHOD();
1202
6
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1203
6
  }
1204
1205
3.68k
  proto = parent->common.prototype ?
1206
3.30k
    parent->common.prototype : parent;
1207
1208
3.68k
  if (parent_flags & ZEND_ACC_CTOR) {
1209
    /* ctors only have a prototype if is abstract (or comes from an interface) */
1210
    /* and if that is the case, we want to check inheritance against it */
1211
203
    if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1212
76
      return INHERITANCE_SUCCESS;
1213
76
    }
1214
127
    parent = proto;
1215
127
  }
1216
1217
3.60k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_PROTO)
1218
1.82k
   && child->common.prototype != proto) {
1219
1.49k
    SEPARATE_METHOD();
1220
1.49k
    child->common.prototype = proto;
1221
1.49k
  }
1222
1223
  /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1224
3.60k
  if ((flags & ZEND_INHERITANCE_CHECK_VISIBILITY)
1225
3.28k
      && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1226
10
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1227
7
      return INHERITANCE_ERROR;
1228
7
    }
1229
3
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1230
3
      "Access level to %s::%s() must be %s (as in class %s)%s",
1231
3
      ZEND_FN_SCOPE_NAME(child), ZSTR_VAL(child->common.function_name), zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1232
10
  }
1233
1234
3.59k
  if (flags & ZEND_INHERITANCE_CHECK_PROTO) {
1235
3.27k
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1236
1.77k
      return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1237
1.77k
    }
1238
1.50k
    perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1239
1.50k
  }
1240
1241
1.82k
  if ((flags & ZEND_INHERITANCE_RESET_CHILD_OVERRIDE)
1242
1.52k
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1243
8
    SEPARATE_METHOD();
1244
8
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1245
8
  }
1246
1247
1.82k
#undef SEPARATE_METHOD
1248
1249
1.82k
  return INHERITANCE_SUCCESS;
1250
3.59k
}
1251
/* }}} */
1252
1253
static void do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce, bool is_interface, uint32_t flags) /* {{{ */
1254
18.7k
{
1255
18.7k
  zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1256
1257
18.7k
  if (child) {
1258
1.58k
    zend_function *func = (zend_function*)Z_PTR_P(child);
1259
1260
1.58k
    if (is_interface && UNEXPECTED(func == parent)) {
1261
      /* The same method in interface may be inherited few times */
1262
0
      return;
1263
0
    }
1264
1265
1.58k
    do_inheritance_check_on_method(
1266
1.58k
      func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1267
17.1k
  } else {
1268
1269
17.1k
    if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1270
52
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1271
52
    }
1272
1273
17.1k
    parent = zend_duplicate_function(parent, ce);
1274
1275
17.1k
    if (!is_interface) {
1276
17.1k
      _zend_hash_append_ptr(&ce->function_table, key, parent);
1277
17.1k
    } else {
1278
40
      zend_hash_add_new_ptr(&ce->function_table, key, parent);
1279
40
    }
1280
17.1k
  }
1281
18.7k
}
1282
/* }}} */
1283
1284
static inheritance_status full_property_types_compatible(
1285
    const zend_property_info *parent_info, const zend_property_info *child_info,
1286
2.38k
    prop_variance variance) {
1287
2.38k
  if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
1288
1.82k
      && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1289
723
    return INHERITANCE_SUCCESS;
1290
723
  }
1291
1292
1.66k
  if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1293
5
    return INHERITANCE_ERROR;
1294
5
  }
1295
1296
  /* Perform a covariant type check in both directions to determined invariance. */
1297
1.66k
  inheritance_status status1 = variance == PROP_CONTRAVARIANT ? INHERITANCE_SUCCESS :
1298
1.66k
    zend_perform_covariant_type_check(
1299
1.55k
      child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1300
1.66k
  inheritance_status status2 = variance == PROP_COVARIANT ? INHERITANCE_SUCCESS :
1301
1.66k
    zend_perform_covariant_type_check(
1302
1.60k
      parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1303
1.66k
  if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1304
650
    return INHERITANCE_SUCCESS;
1305
650
  }
1306
1.01k
  if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1307
475
    return INHERITANCE_ERROR;
1308
475
  }
1309
536
  ZEND_ASSERT(status1 == INHERITANCE_UNRESOLVED || status2 == INHERITANCE_UNRESOLVED);
1310
536
  return INHERITANCE_UNRESOLVED;
1311
536
}
1312
1313
static ZEND_COLD void emit_incompatible_property_error(
1314
33
    const zend_property_info *child, const zend_property_info *parent, prop_variance variance) {
1315
33
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1316
33
  zend_error_noreturn(E_COMPILE_ERROR,
1317
33
    "Type of %s::$%s must be %s%s (as in class %s)",
1318
33
    ZSTR_VAL(child->ce->name),
1319
33
    zend_get_unmangled_property_name(child->name),
1320
33
    variance == PROP_INVARIANT ? "" :
1321
33
    variance == PROP_COVARIANT ? "subtype of " : "supertype of ",
1322
33
    ZSTR_VAL(type_str),
1323
33
    ZSTR_VAL(parent->ce->name));
1324
33
}
1325
1326
static ZEND_COLD void emit_set_hook_type_error(const zend_property_info *child, const zend_property_info *parent)
1327
0
{
1328
0
  zend_type set_type = parent->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1329
0
  zend_string *type_str = zend_type_to_string_resolved(set_type, parent->ce);
1330
0
  zend_error_noreturn(E_COMPILE_ERROR,
1331
0
    "Set type of %s::$%s must be supertype of %s (as in %s %s)",
1332
0
    ZSTR_VAL(child->ce->name),
1333
0
    zend_get_unmangled_property_name(child->name),
1334
0
    ZSTR_VAL(type_str),
1335
0
    zend_get_object_type_case(parent->ce, false),
1336
0
    ZSTR_VAL(parent->ce->name));
1337
0
}
1338
1339
static inheritance_status verify_property_type_compatibility(
1340
  const zend_property_info *parent_info,
1341
  const zend_property_info *child_info,
1342
  prop_variance variance,
1343
  bool throw_on_error,
1344
  bool throw_on_unresolved
1345
2.38k
) {
1346
2.38k
  inheritance_status result = full_property_types_compatible(parent_info, child_info, variance);
1347
2.38k
  if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1348
33
    emit_incompatible_property_error(child_info, parent_info, variance);
1349
33
  }
1350
2.38k
  if (result != INHERITANCE_SUCCESS) {
1351
983
    return result;
1352
983
  }
1353
1.40k
  if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1354
100
    ZEND_ASSERT(parent_info->hooks);
1355
100
    if (parent_info->hooks[ZEND_PROPERTY_HOOK_SET]
1356
78
     && (!child_info->hooks || !child_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1357
64
      zend_type set_type = parent_info->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1358
64
      inheritance_status result = zend_perform_covariant_type_check(
1359
64
        parent_info->ce, set_type, child_info->ce, child_info->type);
1360
64
      if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1361
0
        emit_set_hook_type_error(child_info, parent_info);
1362
0
      }
1363
64
    }
1364
100
  }
1365
1.40k
  return INHERITANCE_SUCCESS;
1366
1.40k
}
1367
1368
static bool property_has_operation(const zend_property_info *prop_info, zend_property_hook_kind kind)
1369
51
{
1370
51
  return (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1371
46
      && (kind == ZEND_PROPERTY_HOOK_GET || !(prop_info->flags & ZEND_ACC_READONLY)))
1372
6
    || (prop_info->hooks && prop_info->hooks[kind]);
1373
51
}
1374
1375
static void inherit_property_hook(
1376
  zend_class_entry *ce,
1377
  zend_property_info *parent_info,
1378
  zend_property_info *child_info,
1379
  zend_property_hook_kind kind
1380
1.05k
) {
1381
1.05k
  zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
1382
1.05k
  zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;
1383
1384
1.05k
  if (child
1385
511
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)
1386
8
   && property_has_operation(parent_info, kind)) {
1387
6
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1388
6
  }
1389
1390
1.05k
  if (!parent) {
1391
618
    return;
1392
618
  }
1393
1394
440
  if (!child) {
1395
113
    if (parent->common.fn_flags & ZEND_ACC_ABSTRACT) {
1396
      /* Backed properties are considered to always implement get, and set when they are not readonly. */
1397
43
      if (property_has_operation(child_info, kind)) {
1398
39
        return;
1399
39
      }
1400
4
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1401
4
    }
1402
74
    if (!child_info->hooks) {
1403
28
      ce->num_hooked_props++;
1404
28
      child_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1405
28
      memset(child_info->hooks, 0, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1406
28
    }
1407
74
    child_info->hooks[kind] = zend_duplicate_function(parent, ce);
1408
74
    return;
1409
113
  }
1410
1411
327
  child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1412
1413
327
  uint32_t parent_flags = parent->common.fn_flags;
1414
327
  if (parent_flags & ZEND_ACC_PRIVATE) {
1415
0
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1416
0
    return;
1417
0
  }
1418
1419
327
  if (parent_flags & ZEND_ACC_FINAL) {
1420
1
    zend_error_noreturn(E_COMPILE_ERROR,
1421
1
      "Cannot override final property hook %s::%s()",
1422
1
      ZSTR_VAL(parent->common.scope->name),
1423
1
      ZSTR_VAL(parent->common.function_name));
1424
1
  }
1425
1426
326
  do_inheritance_check_on_method(
1427
326
    child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
1428
326
    ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY
1429
326
      | ZEND_INHERITANCE_SET_CHILD_CHANGED | ZEND_INHERITANCE_SET_CHILD_PROTO
1430
326
      | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
1431
1432
  /* Other signature compatibility issues should already be covered either by the
1433
   * properties being compatible (types), or certain signatures being forbidden by the
1434
   * compiler (variadic and by-ref args, etc). */
1435
326
}
1436
1437
2.73k
static prop_variance prop_get_variance(const zend_property_info *prop_info) {
1438
2.73k
  bool unbacked = prop_info->flags & ZEND_ACC_VIRTUAL;
1439
2.73k
  if (unbacked && prop_info->hooks) {
1440
353
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1441
147
      return PROP_COVARIANT;
1442
147
    }
1443
206
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
1444
112
      return PROP_CONTRAVARIANT;
1445
112
    }
1446
206
  }
1447
2.47k
  return PROP_INVARIANT;
1448
2.73k
}
1449
1450
static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1451
2.99k
{
1452
2.99k
  zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1453
1454
2.99k
  if (UNEXPECTED(child)) {
1455
844
    zend_property_info *child_info = Z_PTR_P(child);
1456
844
    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1457
16
      child_info->flags |= ZEND_ACC_CHANGED;
1458
16
    }
1459
844
    if (parent_info->flags & ZEND_ACC_FINAL) {
1460
1
      zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final property %s::$%s",
1461
1
        ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key));
1462
1
    }
1463
843
    if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1464
828
      if (!(parent_info->ce->ce_flags & ZEND_ACC_INTERFACE)) {
1465
828
        child_info->prototype = parent_info->prototype;
1466
828
      }
1467
1468
828
      if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
1469
9
        zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1470
9
          (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1471
9
          (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
1472
9
      }
1473
819
      if (UNEXPECTED((child_info->flags & ZEND_ACC_READONLY) != (parent_info->flags & ZEND_ACC_READONLY))) {
1474
2
        if (!(parent_info->flags & ZEND_ACC_ABSTRACT)) {
1475
1
          zend_error_noreturn(E_COMPILE_ERROR,
1476
1
            "Cannot redeclare %s property %s::$%s as %s %s::$%s",
1477
1
            parent_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1478
1
            ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1479
1
            child_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1480
1
            ZSTR_VAL(ce->name), ZSTR_VAL(key));
1481
1
        }
1482
2
      }
1483
818
      if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_SET_MASK))
1484
       /* Get-only virtual properties have no set visibility, so any child visibility is fine. */
1485
30
       && !(parent_info->hooks && (parent_info->flags & ZEND_ACC_VIRTUAL) && !parent_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1486
19
        uint32_t parent_set_visibility = parent_info->flags & ZEND_ACC_PPP_SET_MASK;
1487
        /* Adding set protection is fine if it's the same or weaker than
1488
         * the parents full property visibility. */
1489
19
        if (!parent_set_visibility) {
1490
3
          parent_set_visibility = zend_visibility_to_set_visibility(parent_info->flags & ZEND_ACC_PPP_MASK);
1491
3
        }
1492
19
        uint32_t child_set_visibility = child_info->flags & ZEND_ACC_PPP_SET_MASK;
1493
19
        if (child_set_visibility > parent_set_visibility) {
1494
3
          zend_error_noreturn(
1495
3
            E_COMPILE_ERROR,
1496
3
            "Set access level of %s::$%s must be %s (as in class %s)%s",
1497
3
            ZSTR_VAL(ce->name), ZSTR_VAL(key),
1498
3
            zend_asymmetric_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name),
1499
3
            !(parent_info->flags & ZEND_ACC_PPP_SET_MASK) ? "" : " or weaker");
1500
3
        }
1501
19
      }
1502
1503
815
      if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1504
1
        zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ZSTR_VAL(ce->name), ZSTR_VAL(key), zend_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name), (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1505
1
      }
1506
814
      if (!(child_info->flags & ZEND_ACC_STATIC) && !(parent_info->flags & ZEND_ACC_VIRTUAL)) {
1507
        /* If we added hooks to the child property, we use the child's slot for
1508
         * storage to keep the parent slot set to IS_UNDEF. This automatically
1509
         * picks the slow path in the JIT. */
1510
601
        bool use_child_prop = !parent_info->hooks && child_info->hooks;
1511
1512
601
        if (use_child_prop && child_info->offset == ZEND_VIRTUAL_PROPERTY_OFFSET) {
1513
92
          child_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
1514
92
          ce->default_properties_count++;
1515
92
          ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1516
92
          zval *property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(child_info->offset)];
1517
92
          ZVAL_UNDEF(property_default_ptr);
1518
92
          Z_PROP_FLAG_P(property_default_ptr) = IS_PROP_UNINIT;
1519
92
        }
1520
1521
601
        int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
1522
601
        if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1523
          /* Don't keep default properties in GC (they may be freed by opcache) */
1524
403
          zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1525
1526
403
          if (use_child_prop) {
1527
133
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1528
270
          } else {
1529
270
            int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1530
270
            ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1531
270
            ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1532
270
          }
1533
403
        } else {
1534
          /* Default value was removed in child, remove it from parent too. */
1535
198
          if (ZEND_TYPE_IS_SET(child_info->type)) {
1536
77
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1537
121
          } else {
1538
121
            ZVAL_NULL(&ce->default_properties_table[parent_num]);
1539
121
          }
1540
198
        }
1541
1542
601
        if (!use_child_prop) {
1543
468
          child_info->offset = parent_info->offset;
1544
468
        }
1545
601
        child_info->flags &= ~ZEND_ACC_VIRTUAL;
1546
601
      }
1547
1548
814
      if (parent_info->hooks || child_info->hooks) {
1549
1.59k
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1550
1.05k
          inherit_property_hook(ce, parent_info, child_info, i);
1551
1.05k
        }
1552
533
      }
1553
1554
814
      prop_variance variance = prop_get_variance(parent_info);
1555
814
      if (ZEND_TYPE_IS_SET(parent_info->type)) {
1556
456
        inheritance_status status = verify_property_type_compatibility(
1557
456
          parent_info, child_info, variance, true, false);
1558
456
        if (status == INHERITANCE_UNRESOLVED) {
1559
0
          add_property_compatibility_obligation(ce, child_info, parent_info, variance);
1560
0
        }
1561
456
      } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1562
3
        zend_error_noreturn(E_COMPILE_ERROR,
1563
3
            "Type of %s::$%s must be omitted to match the parent definition in class %s",
1564
3
            ZSTR_VAL(ce->name),
1565
3
            ZSTR_VAL(key),
1566
3
            ZSTR_VAL(parent_info->ce->name));
1567
3
      }
1568
1569
811
      if (child_info->ce == ce) {
1570
767
        child_info->flags &= ~ZEND_ACC_OVERRIDE;
1571
767
      }
1572
811
    }
1573
2.15k
  } else {
1574
2.15k
    zend_function **hooks = parent_info->hooks;
1575
2.15k
    if (hooks) {
1576
69
      ce->num_hooked_props++;
1577
69
      if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1578
12
        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1579
12
      }
1580
69
    }
1581
1582
2.15k
    _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1583
2.15k
  }
1584
2.99k
}
1585
/* }}} */
1586
1587
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1588
2.91k
{
1589
2.91k
  if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
1590
0
    zend_error_noreturn(E_CORE_ERROR, "%s %s could not implement interface %s", zend_get_object_type_uc(ce), ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1591
0
  }
1592
  /* This should be prevented by the class lookup logic. */
1593
2.91k
  ZEND_ASSERT(ce != iface);
1594
2.91k
}
1595
/* }}} */
1596
1597
static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1598
696
{
1599
  /* expects interface to be contained in ce's interface list already */
1600
696
  uint32_t i, ce_num, if_num = iface->num_interfaces;
1601
1602
696
  ce_num = ce->num_interfaces;
1603
1604
696
  if (ce->type == ZEND_INTERNAL_CLASS) {
1605
236
    ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1606
460
  } else {
1607
460
    ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1608
460
  }
1609
1610
  /* Inherit the interfaces, only if they're not already inherited by the class */
1611
3.47k
  while (if_num--) {
1612
2.78k
    zend_class_entry *entry = iface->interfaces[if_num];
1613
2.92k
    for (i = 0; i < ce_num; i++) {
1614
198
      if (ce->interfaces[i] == entry) {
1615
56
        break;
1616
56
      }
1617
198
    }
1618
2.78k
    if (i == ce_num) {
1619
2.72k
      ce->interfaces[ce->num_interfaces++] = entry;
1620
2.72k
    }
1621
2.78k
  }
1622
696
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1623
1624
  /* and now call the implementing handlers */
1625
3.42k
  while (ce_num < ce->num_interfaces) {
1626
2.72k
    do_implement_interface(ce, ce->interfaces[ce_num++]);
1627
2.72k
  }
1628
696
}
1629
/* }}} */
1630
1631
static void emit_incompatible_class_constant_error(
1632
3
    const zend_class_constant *child, const zend_class_constant *parent, const zend_string *const_name) {
1633
3
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1634
3
  zend_error_noreturn(E_COMPILE_ERROR,
1635
3
    "Type of %s::%s must be compatible with %s::%s of type %s",
1636
3
    ZSTR_VAL(child->ce->name),
1637
3
    ZSTR_VAL(const_name),
1638
3
    ZSTR_VAL(parent->ce->name),
1639
3
    ZSTR_VAL(const_name),
1640
3
    ZSTR_VAL(type_str));
1641
3
}
1642
1643
static inheritance_status class_constant_types_compatible(const zend_class_constant *parent, const zend_class_constant *child)
1644
181
{
1645
181
  ZEND_ASSERT(ZEND_TYPE_IS_SET(parent->type));
1646
1647
181
  if (!ZEND_TYPE_IS_SET(child->type)) {
1648
2
    return INHERITANCE_ERROR;
1649
2
  }
1650
1651
179
  return zend_perform_covariant_type_check(child->ce, child->type, parent->ce, parent->type);
1652
181
}
1653
1654
static bool do_inherit_constant_check(
1655
  zend_class_entry *ce, const zend_class_constant *parent_constant, zend_string *name);
1656
1657
static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
1658
5.60k
{
1659
5.60k
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1660
5.60k
  zend_class_constant *c;
1661
1662
5.60k
  if (zv != NULL) {
1663
57
    c = (zend_class_constant*)Z_PTR_P(zv);
1664
57
    bool inherit = do_inherit_constant_check(ce, parent_const, name);
1665
57
    ZEND_ASSERT(!inherit);
1666
5.55k
  } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1667
5.53k
    if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1668
66
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1669
66
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1670
66
      if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
1671
0
        c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1672
0
        memcpy(c, parent_const, sizeof(zend_class_constant));
1673
0
        parent_const = c;
1674
0
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1675
0
      }
1676
66
    }
1677
5.53k
    if (ce->type & ZEND_INTERNAL_CLASS) {
1678
150
      c = pemalloc(sizeof(zend_class_constant), 1);
1679
150
      memcpy(c, parent_const, sizeof(zend_class_constant));
1680
150
      parent_const = c;
1681
150
    }
1682
5.53k
    _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1683
5.53k
  }
1684
5.60k
}
1685
/* }}} */
1686
1687
void zend_build_properties_info_table(zend_class_entry *ce)
1688
48.7k
{
1689
48.7k
  zend_property_info **table, *prop;
1690
48.7k
  size_t size;
1691
48.7k
  if (ce->default_properties_count == 0) {
1692
33.8k
    return;
1693
33.8k
  }
1694
1695
14.9k
  ZEND_ASSERT(ce->properties_info_table == NULL);
1696
14.9k
  size = sizeof(zend_property_info *) * ce->default_properties_count;
1697
14.9k
  if (ce->type == ZEND_USER_CLASS) {
1698
14.8k
    ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1699
14.8k
  } else {
1700
102
    ce->properties_info_table = table = pemalloc(size, 1);
1701
102
  }
1702
1703
  /* Dead slots may be left behind during inheritance. Make sure these are NULLed out. */
1704
14.9k
  memset(table, 0, size);
1705
1706
14.9k
  if (ce->parent && ce->parent->default_properties_count != 0) {
1707
766
    zend_property_info **parent_table = ce->parent->properties_info_table;
1708
766
    memcpy(
1709
766
      table, parent_table,
1710
766
      sizeof(zend_property_info *) * ce->parent->default_properties_count
1711
766
    );
1712
1713
    /* Child did not add any new properties, we are done */
1714
766
    if (ce->default_properties_count == ce->parent->default_properties_count) {
1715
396
      return;
1716
396
    }
1717
766
  }
1718
1719
62.3k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, prop) {
1720
62.3k
    if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0
1721
15.7k
     && !(prop->flags & ZEND_ACC_VIRTUAL)) {
1722
15.5k
      const zend_property_info *root_prop = prop->prototype;
1723
15.5k
      if (UNEXPECTED(root_prop->flags & ZEND_ACC_VIRTUAL)) {
1724
        /* Prototype is virtual, we need to manually hunt down the first backed property. */
1725
41
        root_prop = prop;
1726
41
        zend_class_entry *parent_ce;
1727
47
        while ((parent_ce = root_prop->ce->parent)) {
1728
47
          zend_property_info *parent_prop = zend_hash_find_ptr(&parent_ce->properties_info, key);
1729
47
          if (!parent_prop
1730
47
           || parent_prop->prototype != prop->prototype
1731
47
           || (parent_prop->flags & ZEND_ACC_VIRTUAL)) {
1732
41
            break;
1733
41
          }
1734
6
          root_prop = parent_prop;
1735
6
        }
1736
41
      }
1737
15.5k
      uint32_t prop_table_offset = OBJ_PROP_TO_NUM(root_prop->offset);
1738
15.5k
      table[prop_table_offset] = prop;
1739
15.5k
    }
1740
62.3k
  } ZEND_HASH_FOREACH_END();
1741
14.5k
}
1742
1743
ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name)
1744
1.54k
{
1745
1.54k
  if (!prop_info->hooks) {
1746
0
    return;
1747
0
  }
1748
1.54k
  bool abstract_error = prop_info->flags & ZEND_ACC_ABSTRACT;
1749
  /* We specified a default value (otherwise offset would be -1), but the virtual flag wasn't
1750
   * removed during inheritance. */
1751
1.54k
  if ((prop_info->flags & ZEND_ACC_VIRTUAL) && prop_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1752
4
    if (Z_TYPE(ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]) == IS_UNDEF) {
1753
0
      prop_info->offset = ZEND_VIRTUAL_PROPERTY_OFFSET;
1754
4
    } else {
1755
4
      zend_error_noreturn(E_COMPILE_ERROR,
1756
4
        "Cannot specify default value for virtual hooked property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1757
4
    }
1758
4
  }
1759
  /* If the property turns backed during inheritance and no type and default value are set, we want
1760
   * the default value to be null. */
1761
1.53k
  if (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1762
563
   && !ZEND_TYPE_IS_SET(prop_info->type)
1763
331
   && Z_TYPE(ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]) == IS_UNDEF) {
1764
173
    ZVAL_NULL(&ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]);
1765
173
  }
1766
4.60k
  for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1767
3.07k
    const zend_function *func = prop_info->hooks[i];
1768
3.07k
    if (func) {
1769
1.81k
      if ((zend_property_hook_kind)i == ZEND_PROPERTY_HOOK_GET
1770
1.23k
       && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1771
160
       && !(prop_info->flags & ZEND_ACC_VIRTUAL)
1772
38
       && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1773
1
        zend_error_noreturn(E_COMPILE_ERROR, "Get hook of backed property %s::%s with set hook may not return by reference",
1774
1
          ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1775
1
      }
1776
1.81k
      if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
1777
373
        abstract_error = false;
1778
373
      }
1779
1.81k
    }
1780
3.07k
  }
1781
1.53k
  if (abstract_error) {
1782
2
    zend_error_noreturn(E_COMPILE_ERROR,
1783
2
      "Abstract property %s::$%s must specify at least one abstract hook", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1784
2
  }
1785
1.53k
  if ((prop_info->flags & ZEND_ACC_VIRTUAL)
1786
972
   && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)
1787
7
   && (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET] || !prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1788
2
    const char *prefix = !prop_info->hooks[ZEND_PROPERTY_HOOK_GET]
1789
2
      ? "set-only" : "get-only";
1790
2
    zend_error_noreturn(E_COMPILE_ERROR,
1791
2
      "%s virtual property %s::$%s must not specify asymmetric visibility",
1792
2
      prefix, ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1793
2
  }
1794
1.53k
}
1795
1796
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name)
1797
2
{
1798
2
  zend_error_noreturn(E_COMPILE_ERROR, "Type of parameter $%s of hook %s::$%s::set must be compatible with property type",
1799
2
    ZSTR_VAL(value_param_name), ZSTR_VAL(class_name), zend_get_unmangled_property_name(prop_name));
1800
2
}
1801
1802
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info)
1803
1
{
1804
1
  zend_string *value_param_name = prop_info->hooks[ZEND_PROPERTY_HOOK_SET]->op_array.arg_info[0].name;
1805
1
  zend_hooked_property_variance_error_ex(value_param_name, prop_info->ce->name, prop_info->name);
1806
1
}
1807
1808
ZEND_API inheritance_status zend_verify_property_hook_variance(const zend_property_info *prop_info, const zend_function *func)
1809
702
{
1810
702
  ZEND_ASSERT(prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET] == func);
1811
1812
702
  zend_arg_info *value_arg_info = &func->op_array.arg_info[0];
1813
702
  if (!ZEND_TYPE_IS_SET(value_arg_info->type)) {
1814
355
    return INHERITANCE_SUCCESS;
1815
355
  }
1816
1817
347
  if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1818
0
    return INHERITANCE_ERROR;
1819
0
  }
1820
1821
347
  zend_class_entry *ce = prop_info->ce;
1822
347
  return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type);
1823
347
}
1824
1825
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
1826
/* Hooked properties set get_iterator, which causes issues on for shm
1827
 * reattachment. Avoid early-binding on Windows and set get_iterator during
1828
 * inheritance. The linked class may not use inheritance cache. */
1829
static void zend_link_hooked_object_iter(zend_class_entry *ce) {
1830
  if (!ce->get_iterator && ce->num_hooked_props) {
1831
    ce->get_iterator = zend_hooked_object_get_iterator;
1832
    ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
1833
    if (CG(current_linking_class) == ce) {
1834
# if ZEND_DEBUG
1835
      /* This check is executed before inheriting any elements that can
1836
       * track dependencies. */
1837
      HashTable *ht = (HashTable*)ce->inheritance_cache;
1838
      ZEND_ASSERT(!ht);
1839
# endif
1840
      CG(current_linking_class) = NULL;
1841
    }
1842
  }
1843
}
1844
#endif
1845
1846
ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked) /* {{{ */
1847
2.59k
{
1848
2.59k
  zend_property_info *property_info;
1849
2.59k
  zend_string *key;
1850
1851
2.59k
  if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) {
1852
    /* Interface can only inherit other interfaces */
1853
0
    if (UNEXPECTED(!(parent_ce->ce_flags & ZEND_ACC_INTERFACE))) {
1854
0
      zend_error_noreturn(E_COMPILE_ERROR, "Interface %s cannot extend class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1855
0
    }
1856
2.59k
  } else if (UNEXPECTED(parent_ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_FINAL|ZEND_ACC_ENUM))) {
1857
    /* Class must not extend an enum (GH-16315); check enums first since
1858
     * enums are implemented as final classes */
1859
6
    if (parent_ce->ce_flags & ZEND_ACC_ENUM) {
1860
1
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend enum %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1861
1
    }
1862
    /* Class must not extend a final class */
1863
5
    if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1864
2
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1865
2
    }
1866
1867
    /* Class declaration must not extend traits or interfaces */
1868
3
    if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1869
3
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1870
3
        ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1871
3
      );
1872
3
    }
1873
3
  }
1874
1875
2.58k
  if (UNEXPECTED((ce->ce_flags & ZEND_ACC_READONLY_CLASS) != (parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS))) {
1876
1
    zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1877
1
      ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1878
1
      parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1879
1
    );
1880
1
  }
1881
1882
2.58k
  if (ce->parent_name) {
1883
2.43k
    zend_string_release_ex(ce->parent_name, 0);
1884
2.43k
  }
1885
2.58k
  ce->parent = parent_ce;
1886
2.58k
  ce->default_object_handlers = parent_ce->default_object_handlers;
1887
2.58k
  ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1888
1889
  /* Inherit properties */
1890
2.58k
  if (parent_ce->default_properties_count) {
1891
822
    zval *src, *dst, *end;
1892
1893
822
    if (ce->default_properties_count) {
1894
361
      zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1895
361
      src = ce->default_properties_table + ce->default_properties_count;
1896
361
      end = table + parent_ce->default_properties_count;
1897
361
      dst = end + ce->default_properties_count;
1898
361
      ce->default_properties_table = table;
1899
484
      do {
1900
484
        dst--;
1901
484
        src--;
1902
484
        ZVAL_COPY_VALUE_PROP(dst, src);
1903
484
      } while (dst != end);
1904
361
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1905
361
      end = ce->default_properties_table;
1906
461
    } else {
1907
461
      end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1908
461
      dst = end + parent_ce->default_properties_count;
1909
461
      ce->default_properties_table = end;
1910
461
    }
1911
822
    src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1912
822
    if (UNEXPECTED(parent_ce->type != ce->type)) {
1913
      /* User class extends internal */
1914
552
      do {
1915
552
        dst--;
1916
552
        src--;
1917
        /* We don't have to account for refcounting because
1918
         * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1919
552
        ZEND_ASSERT(!Z_REFCOUNTED_P(src));
1920
552
        ZVAL_COPY_VALUE_PROP(dst, src);
1921
552
        if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1922
0
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1923
0
          ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1924
0
        }
1925
552
        continue;
1926
552
      } while (dst != end);
1927
741
    } else {
1928
2.17k
      do {
1929
2.17k
        dst--;
1930
2.17k
        src--;
1931
2.17k
        ZVAL_COPY_PROP(dst, src);
1932
2.17k
        if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1933
136
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1934
136
          ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1935
136
        }
1936
2.17k
        continue;
1937
2.17k
      } while (dst != end);
1938
741
    }
1939
822
    ce->default_properties_count += parent_ce->default_properties_count;
1940
822
  }
1941
1942
2.58k
  if (parent_ce->default_static_members_count) {
1943
128
    zval *src, *dst, *end;
1944
1945
128
    if (ce->default_static_members_count) {
1946
80
      zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1947
80
      src = ce->default_static_members_table + ce->default_static_members_count;
1948
80
      end = table + parent_ce->default_static_members_count;
1949
80
      dst = end + ce->default_static_members_count;
1950
80
      ce->default_static_members_table = table;
1951
172
      do {
1952
172
        dst--;
1953
172
        src--;
1954
172
        ZVAL_COPY_VALUE(dst, src);
1955
172
      } while (dst != end);
1956
80
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1957
80
      end = ce->default_static_members_table;
1958
80
    } else {
1959
48
      end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1960
48
      dst = end + parent_ce->default_static_members_count;
1961
48
      ce->default_static_members_table = end;
1962
48
    }
1963
128
    src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1964
275
    do {
1965
275
      dst--;
1966
275
      src--;
1967
275
      if (Z_TYPE_P(src) == IS_INDIRECT) {
1968
50
        ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1969
225
      } else {
1970
225
        ZVAL_INDIRECT(dst, src);
1971
225
      }
1972
275
      if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1973
52
        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1974
52
        ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
1975
52
      }
1976
275
    } while (dst != end);
1977
128
    ce->default_static_members_count += parent_ce->default_static_members_count;
1978
128
    if (!ZEND_MAP_PTR(ce->static_members_table)) {
1979
128
      if (ce->type == ZEND_INTERNAL_CLASS &&
1980
0
          ce->info.internal.module->type == MODULE_PERSISTENT) {
1981
0
        ZEND_MAP_PTR_NEW(ce->static_members_table);
1982
0
      }
1983
128
    }
1984
128
  }
1985
1986
8.26k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1987
8.26k
    if (property_info->ce == ce) {
1988
1.54k
      if (property_info->flags & ZEND_ACC_STATIC) {
1989
195
        property_info->offset += parent_ce->default_static_members_count;
1990
1.34k
      } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1991
799
        property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1992
799
      }
1993
1.54k
    }
1994
8.26k
  } ZEND_HASH_FOREACH_END();
1995
1996
2.58k
  if (zend_hash_num_elements(&parent_ce->properties_info)) {
1997
1.00k
    zend_hash_extend(&ce->properties_info,
1998
1.00k
      zend_hash_num_elements(&ce->properties_info) +
1999
1.00k
      zend_hash_num_elements(&parent_ce->properties_info), 0);
2000
2001
8.00k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
2002
8.00k
      do_inherit_property(property_info, key, ce);
2003
8.00k
    } ZEND_HASH_FOREACH_END();
2004
1.00k
  }
2005
2006
2.58k
  if (ce->num_hooked_props) {
2007
2.41k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
2008
2.41k
      if (property_info->ce == ce && property_info->hooks) {
2009
612
        zend_verify_hooked_property(ce, property_info, key);
2010
612
      }
2011
2.41k
    } ZEND_HASH_FOREACH_END();
2012
293
  }
2013
2014
2.58k
  if (zend_hash_num_elements(&parent_ce->constants_table)) {
2015
824
    zend_class_constant *c;
2016
2017
824
    zend_hash_extend(&ce->constants_table,
2018
824
      zend_hash_num_elements(&ce->constants_table) +
2019
824
      zend_hash_num_elements(&parent_ce->constants_table), 0);
2020
2021
12.8k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
2022
12.8k
      do_inherit_class_constant(key, c, ce);
2023
12.8k
    } ZEND_HASH_FOREACH_END();
2024
824
  }
2025
2026
2.58k
  if (zend_hash_num_elements(&parent_ce->function_table)) {
2027
1.59k
    zend_hash_extend(&ce->function_table,
2028
1.59k
      zend_hash_num_elements(&ce->function_table) +
2029
1.59k
      zend_hash_num_elements(&parent_ce->function_table), 0);
2030
1.59k
    uint32_t flags =
2031
1.59k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2032
1.59k
      ZEND_INHERITANCE_SET_CHILD_CHANGED |
2033
1.59k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2034
1.59k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2035
2036
1.59k
    if (!checked) {
2037
761
      flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2038
761
    }
2039
1.59k
    zend_function *func;
2040
39.6k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
2041
39.6k
      do_inherit_method(key, func, ce, false, flags);
2042
39.6k
    } ZEND_HASH_FOREACH_END();
2043
1.59k
  }
2044
2045
2.58k
  do_inherit_parent_constructor(ce);
2046
2047
2.58k
  if (ce->type == ZEND_INTERNAL_CLASS) {
2048
156
    if (parent_ce->num_interfaces) {
2049
156
      zend_do_inherit_interfaces(ce, parent_ce);
2050
156
    }
2051
2052
156
    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
2053
4
      ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
2054
4
    }
2055
156
  }
2056
2.58k
  ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_READONLY_PROPS | ZEND_ACC_USE_GUARDS | ZEND_ACC_NOT_SERIALIZABLE | ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES);
2057
2.58k
}
2058
/* }}} */
2059
2060
static zend_always_inline bool check_trait_property_or_constant_value_compatibility(zend_class_entry *ce, zval *op1, zval *op2) /* {{{ */
2061
0
{
2062
0
  bool is_compatible;
2063
0
  zval op1_tmp, op2_tmp;
2064
2065
  /* if any of the values is a constant, we try to resolve it */
2066
0
  if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
2067
0
    ZVAL_COPY_OR_DUP(&op1_tmp, op1);
2068
0
    if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
2069
0
      zval_ptr_dtor(&op1_tmp);
2070
0
      return false;
2071
0
    }
2072
0
    op1 = &op1_tmp;
2073
0
  }
2074
0
  if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
2075
0
    ZVAL_COPY_OR_DUP(&op2_tmp, op2);
2076
0
    if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
2077
0
      zval_ptr_dtor(&op2_tmp);
2078
0
      return false;
2079
0
    }
2080
0
    op2 = &op2_tmp;
2081
0
  }
2082
2083
0
  is_compatible = fast_is_identical_function(op1, op2);
2084
2085
0
  if (op1 == &op1_tmp) {
2086
0
    zval_ptr_dtor_nogc(&op1_tmp);
2087
0
  }
2088
0
  if (op2 == &op2_tmp) {
2089
0
    zval_ptr_dtor_nogc(&op2_tmp);
2090
0
  }
2091
2092
0
  return is_compatible;
2093
0
}
2094
/* }}} */
2095
2096
/** @return bool Returns true if the class constant should be inherited, i.e. whether it doesn't already exist. */
2097
static bool do_inherit_constant_check(
2098
  zend_class_entry *ce, const zend_class_constant *parent_constant, zend_string *name
2099
113
) {
2100
113
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2101
113
  if (zv == NULL) {
2102
56
    return true;
2103
56
  }
2104
2105
57
  zend_class_constant *child_constant = Z_PTR_P(zv);
2106
57
  if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
2107
1
    zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
2108
1
      ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2109
1
      ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
2110
1
    );
2111
1
  }
2112
2113
56
  if (child_constant->ce != parent_constant->ce && child_constant->ce != ce) {
2114
0
    zend_error_noreturn(E_COMPILE_ERROR,
2115
0
      "%s %s inherits both %s::%s and %s::%s, which is ambiguous",
2116
0
      zend_get_object_type_uc(ce),
2117
0
      ZSTR_VAL(ce->name),
2118
0
      ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2119
0
      ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
2120
0
  }
2121
2122
56
  if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(child_constant) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PPP_MASK))) {
2123
1
    zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in %s %s)%s",
2124
1
      ZSTR_VAL(ce->name), ZSTR_VAL(name),
2125
1
      zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_constant)),
2126
1
      zend_get_object_type(parent_constant->ce),
2127
1
      ZSTR_VAL(parent_constant->ce->name),
2128
1
      (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PUBLIC) ? "" : " or weaker"
2129
1
    );
2130
1
  }
2131
2132
55
  if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
2133
25
    inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
2134
25
    if (status == INHERITANCE_ERROR) {
2135
3
      emit_incompatible_class_constant_error(child_constant, parent_constant, name);
2136
22
    } else if (status == INHERITANCE_UNRESOLVED) {
2137
0
      add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
2138
0
    }
2139
25
  }
2140
2141
55
  return false;
2142
56
}
2143
/* }}} */
2144
2145
static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
2146
56
{
2147
56
  if (do_inherit_constant_check(ce, c, name)) {
2148
56
    zend_class_constant *ct;
2149
56
    if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2150
0
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2151
0
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2152
0
      if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
2153
0
        ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2154
0
        memcpy(ct, c, sizeof(zend_class_constant));
2155
0
        c = ct;
2156
0
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2157
0
      }
2158
0
    }
2159
56
    if (ce->type & ZEND_INTERNAL_CLASS) {
2160
56
      ct = pemalloc(sizeof(zend_class_constant), 1);
2161
56
      memcpy(ct, c, sizeof(zend_class_constant));
2162
56
      c = ct;
2163
56
    }
2164
56
    zend_hash_update_ptr(&ce->constants_table, name, c);
2165
56
  }
2166
56
}
2167
/* }}} */
2168
2169
static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2170
188
{
2171
188
  zend_function *func;
2172
188
  zend_string *key;
2173
188
  zend_class_constant *c;
2174
188
  uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2175
2176
188
  if (!(ce->ce_flags & ZEND_ACC_INTERFACE)) {
2177
    /* We are not setting the prototype of overridden interface methods because of abstract
2178
     * constructors. See Zend/tests/interface_constructor_prototype_001.phpt. */
2179
170
    flags |=
2180
170
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2181
170
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2182
170
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2183
170
  } else {
2184
18
    flags |=
2185
18
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2186
18
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2187
18
  }
2188
2189
488
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2190
488
    do_inherit_iface_constant(key, c, ce, iface);
2191
488
  } ZEND_HASH_FOREACH_END();
2192
2193
1.42k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2194
1.42k
    do_inherit_method(key, func, ce, true, flags);
2195
1.42k
  } ZEND_HASH_FOREACH_END();
2196
2197
188
  zend_hash_extend(&ce->properties_info,
2198
188
    zend_hash_num_elements(&ce->properties_info) +
2199
188
    zend_hash_num_elements(&iface->properties_info), 0);
2200
2201
188
  zend_property_info *prop;
2202
188
  ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2203
188
    do_inherit_property(prop, key, ce);
2204
188
  } ZEND_HASH_FOREACH_END();
2205
2206
188
  do_implement_interface(ce, iface);
2207
188
  if (iface->num_interfaces) {
2208
80
    zend_do_inherit_interfaces(ce, iface);
2209
80
  }
2210
188
}
2211
/* }}} */
2212
2213
ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2214
188
{
2215
188
  bool ignore = false;
2216
188
  uint32_t current_iface_num = ce->num_interfaces;
2217
188
  uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
2218
2219
188
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2220
2221
408
  for (uint32_t i = 0; i < ce->num_interfaces; i++) {
2222
220
    if (ce->interfaces[i] == NULL) {
2223
0
      memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
2224
0
      i--;
2225
220
    } else if (ce->interfaces[i] == iface) {
2226
0
      if (EXPECTED(i < parent_iface_num)) {
2227
0
        ignore = true;
2228
0
      } else {
2229
0
        zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2230
0
      }
2231
0
    }
2232
220
  }
2233
188
  if (ignore) {
2234
0
    zend_string *key;
2235
0
    zend_class_constant *c;
2236
    /* Check for attempt to redeclare interface constants */
2237
0
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2238
0
      do_inherit_constant_check(ce, c, key);
2239
0
    } ZEND_HASH_FOREACH_END();
2240
188
  } else {
2241
188
    if (ce->num_interfaces >= current_iface_num) {
2242
188
      if (ce->type == ZEND_INTERNAL_CLASS) {
2243
188
        ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2244
188
      } else {
2245
0
        ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2246
0
      }
2247
188
    }
2248
188
    ce->interfaces[ce->num_interfaces++] = iface;
2249
2250
188
    do_interface_implementation(ce, iface);
2251
188
  }
2252
188
}
2253
/* }}} */
2254
2255
static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
2256
0
{
2257
0
  uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2258
0
  uint32_t num_interfaces = num_parent_interfaces;
2259
0
  zend_string *key;
2260
0
  zend_class_constant *c;
2261
0
  uint32_t i;
2262
2263
0
  for (i = 0; i < ce->num_interfaces; i++) {
2264
0
    zend_class_entry *iface = interfaces[num_parent_interfaces + i];
2265
0
    if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2266
0
      add_dependency_obligation(ce, iface);
2267
0
    }
2268
0
    if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
2269
0
      efree(interfaces);
2270
0
      zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2271
0
      return;
2272
0
    }
2273
0
    for (uint32_t j = 0; j < num_interfaces; j++) {
2274
0
      if (interfaces[j] == iface) {
2275
0
        if (j >= num_parent_interfaces) {
2276
0
          efree(interfaces);
2277
0
          zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
2278
0
            zend_get_object_type_uc(ce),
2279
0
            ZSTR_VAL(ce->name),
2280
0
            ZSTR_VAL(iface->name));
2281
0
          return;
2282
0
        }
2283
        /* skip duplications */
2284
0
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2285
0
          do_inherit_constant_check(ce, c, key);
2286
0
        } ZEND_HASH_FOREACH_END();
2287
2288
0
        iface = NULL;
2289
0
        break;
2290
0
      }
2291
0
    }
2292
0
    if (iface) {
2293
0
      interfaces[num_interfaces] = iface;
2294
0
      num_interfaces++;
2295
0
    }
2296
0
  }
2297
2298
0
  if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2299
0
    for (i = 0; i < ce->num_interfaces; i++) {
2300
0
      zend_string_release_ex(ce->interface_names[i].name, 0);
2301
0
      zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2302
0
    }
2303
0
    efree(ce->interface_names);
2304
0
  }
2305
2306
0
  ce->num_interfaces = num_interfaces;
2307
0
  ce->interfaces = interfaces;
2308
0
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2309
2310
0
  for (i = 0; i < num_parent_interfaces; i++) {
2311
0
    do_implement_interface(ce, ce->interfaces[i]);
2312
0
  }
2313
  /* Note that new interfaces can be added during this loop due to interface inheritance.
2314
   * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */
2315
0
  for (; i < num_interfaces; i++) {
2316
0
    do_interface_implementation(ce, ce->interfaces[i]);
2317
0
  }
2318
0
}
2319
/* }}} */
2320
2321
2322
void zend_inheritance_check_override(const zend_class_entry *ce)
2323
48.6k
{
2324
48.6k
  if (ce->ce_flags & ZEND_ACC_TRAIT) {
2325
882
    return;
2326
882
  }
2327
2328
140k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *f) {
2329
140k
    if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2330
6
      ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2331
2332
6
      zend_error_at_noreturn(
2333
6
        E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2334
6
        "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2335
6
        ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2336
6
    }
2337
140k
  } ZEND_HASH_FOREACH_END();
2338
2339
134k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
2340
134k
    if (prop->flags & ZEND_ACC_OVERRIDE) {
2341
5
      zend_error_noreturn(
2342
5
        E_COMPILE_ERROR,
2343
5
        "%s::$%s has #[\\Override] attribute, but no matching parent property exists",
2344
5
        ZSTR_VAL(ce->name), zend_get_unmangled_property_name(prop->name));
2345
5
    }
2346
2347
19.5k
    if (prop->hooks) {
2348
4.20k
      for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2349
2.80k
        zend_function *f = prop->hooks[i];
2350
2.80k
        if (f && f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2351
3
          ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2352
2353
3
          zend_error_at_noreturn(
2354
3
            E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2355
3
            "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2356
3
            ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2357
3
        }
2358
2.80k
      }
2359
1.40k
    }
2360
19.5k
  } ZEND_HASH_FOREACH_END();
2361
47.7k
}
2362
2363
2364
static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
2365
0
{
2366
  /* self in trait methods should be resolved to the using class, not the trait. */
2367
0
  return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
2368
0
}
2369
2370
static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
2371
0
{
2372
0
  zend_function *existing_fn = NULL;
2373
0
  zend_function *new_fn;
2374
2375
0
  if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
2376
    /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
2377
     * of where it is coming from there is no conflict and we do not need to add it again */
2378
0
    if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
2379
0
      (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
2380
0
      (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2381
0
      return;
2382
0
    }
2383
2384
    /* Abstract method signatures from the trait must be satisfied. */
2385
0
    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2386
      /* "abstract private" methods in traits were not available prior to PHP 8.
2387
       * As such, "abstract protected" was sometimes used to indicate trait requirements,
2388
       * even though the "implementing" method was private. Do not check visibility
2389
       * requirements to maintain backwards-compatibility with such usage.
2390
       */
2391
0
      do_inheritance_check_on_method(
2392
0
        existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
2393
0
        ce, NULL, ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
2394
0
      return;
2395
0
    }
2396
2397
0
    if (existing_fn->common.scope == ce) {
2398
      /* members from the current class override trait methods */
2399
0
      return;
2400
0
    } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
2401
0
        && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
2402
      /* two traits can't define the same non-abstract method */
2403
0
      zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
2404
0
        ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
2405
0
        ZSTR_VAL(ce->name), ZSTR_VAL(name),
2406
0
        ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
2407
0
    }
2408
0
  }
2409
2410
0
  if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
2411
0
    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
2412
0
    memcpy(new_fn, fn, sizeof(zend_internal_function));
2413
0
    new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
2414
0
  } else {
2415
0
    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2416
0
    memcpy(new_fn, fn, sizeof(zend_op_array));
2417
0
    new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2418
0
  }
2419
0
  new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2420
2421
  /* Reassign method name, in case it is an alias. */
2422
0
  new_fn->common.function_name = name;
2423
0
  function_add_ref(new_fn);
2424
0
  fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2425
0
  zend_add_magic_method(ce, fn, key);
2426
0
}
2427
/* }}} */
2428
2429
static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2430
0
{
2431
0
  if (fn->common.scope->ce_flags & ZEND_ACC_TRAIT) {
2432
2433
0
    fn->common.scope = ce;
2434
2435
0
    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2436
0
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2437
0
    }
2438
0
    if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2439
0
      ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2440
0
    }
2441
0
  }
2442
0
}
2443
/* }}} */
2444
2445
static void zend_traits_check_private_final_inheritance(uint32_t original_fn_flags, const zend_function *fn_copy, const zend_string *name)
2446
0
{
2447
  /* If the function was originally already private+final, then it will have
2448
   * already been warned about. Only emit this error when the used trait method
2449
   * explicitly became final, avoiding errors for `as private` where it was
2450
   * already final. */
2451
0
  if (!(original_fn_flags & ZEND_ACC_FINAL)
2452
0
    && (fn_copy->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2453
0
    && !zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2454
0
    zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2455
0
  }
2456
0
}
2457
2458
static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
2459
0
{
2460
0
  zend_trait_alias  *alias, **alias_ptr;
2461
0
  zend_function      fn_copy;
2462
0
  int                i;
2463
2464
  /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2465
0
  if (ce->trait_aliases) {
2466
0
    alias_ptr = ce->trait_aliases;
2467
0
    alias = *alias_ptr;
2468
0
    i = 0;
2469
0
    while (alias) {
2470
      /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2471
0
      if (alias->alias != NULL
2472
0
        && fn->common.scope == aliases[i]
2473
0
        && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2474
0
      ) {
2475
0
        fn_copy = *fn;
2476
0
        if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2477
0
          fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2478
0
        } else {
2479
0
          fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2480
0
        }
2481
2482
0
        zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2483
2484
0
        zend_string *lcname = zend_string_tolower(alias->alias);
2485
0
        zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2486
0
        zend_string_release_ex(lcname, 0);
2487
0
      }
2488
0
      alias_ptr++;
2489
0
      alias = *alias_ptr;
2490
0
      i++;
2491
0
    }
2492
0
  }
2493
2494
0
  if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2495
    /* is not in hashtable, thus, function is not to be excluded */
2496
0
    memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
2497
2498
    /* apply aliases which have not alias name, just setting visibility */
2499
0
    if (ce->trait_aliases) {
2500
0
      alias_ptr = ce->trait_aliases;
2501
0
      alias = *alias_ptr;
2502
0
      i = 0;
2503
0
      while (alias) {
2504
        /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2505
0
        if (alias->alias == NULL && alias->modifiers != 0
2506
0
          && fn->common.scope == aliases[i]
2507
0
          && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2508
0
        ) {
2509
0
          if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2510
0
            fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2511
0
          } else {
2512
0
            fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2513
0
          }
2514
0
        }
2515
0
        alias_ptr++;
2516
0
        alias = *alias_ptr;
2517
0
        i++;
2518
0
      }
2519
0
    }
2520
2521
0
    zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2522
2523
0
    zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2524
0
  }
2525
0
}
2526
/* }}} */
2527
2528
static uint32_t zend_check_trait_usage(const zend_class_entry *ce, const zend_class_entry *trait, zend_class_entry **traits) /* {{{ */
2529
0
{
2530
0
  if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2531
0
    zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", ZSTR_VAL(trait->name));
2532
0
    return 0;
2533
0
  }
2534
2535
0
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2536
0
    if (traits[i] == trait) {
2537
0
      return i;
2538
0
    }
2539
0
  }
2540
0
  zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
2541
0
  return 0;
2542
0
}
2543
/* }}} */
2544
2545
static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
2546
0
{
2547
0
  size_t i, j = 0;
2548
0
  zend_trait_precedence *cur_precedence;
2549
0
  zend_trait_method_reference *cur_method_ref;
2550
0
  zend_string *lc_trait_name;
2551
0
  zend_string *lcname;
2552
0
  HashTable **exclude_tables = NULL;
2553
0
  zend_class_entry **aliases = NULL;
2554
0
  zend_class_entry *trait;
2555
2556
  /* resolve class references */
2557
0
  if (ce->trait_precedences) {
2558
0
    exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2559
0
    i = 0;
2560
0
    zend_trait_precedence **precedences = ce->trait_precedences;
2561
0
    ce->trait_precedences = NULL;
2562
0
    while ((cur_precedence = precedences[i])) {
2563
      /** Resolve classes for all precedence operations. */
2564
0
      cur_method_ref = &cur_precedence->trait_method;
2565
0
      lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2566
0
      trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2567
0
      zend_string_release_ex(lc_trait_name, 0);
2568
0
      if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2569
0
        zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2570
0
      }
2571
0
      zend_check_trait_usage(ce, trait, traits);
2572
2573
      /** Ensure that the preferred method is actually available. */
2574
0
      lcname = zend_string_tolower(cur_method_ref->method_name);
2575
0
      if (!zend_hash_exists(&trait->function_table, lcname)) {
2576
0
        zend_error_noreturn(E_COMPILE_ERROR,
2577
0
               "A precedence rule was defined for %s::%s but this method does not exist",
2578
0
               ZSTR_VAL(trait->name),
2579
0
               ZSTR_VAL(cur_method_ref->method_name));
2580
0
      }
2581
2582
      /** With the other traits, we are more permissive.
2583
        We do not give errors for those. This allows to be more
2584
        defensive in such definitions.
2585
        However, we want to make sure that the insteadof declaration
2586
        is consistent in itself.
2587
       */
2588
2589
0
      for (j = 0; j < cur_precedence->num_excludes; j++) {
2590
0
        zend_string* class_name = cur_precedence->exclude_class_names[j];
2591
0
        zend_class_entry *exclude_ce;
2592
0
        uint32_t trait_num;
2593
2594
0
        lc_trait_name = zend_string_tolower(class_name);
2595
0
        exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2596
0
        zend_string_release_ex(lc_trait_name, 0);
2597
0
        if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2598
0
          zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2599
0
        }
2600
0
        trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2601
0
        if (!exclude_tables[trait_num]) {
2602
0
          ALLOC_HASHTABLE(exclude_tables[trait_num]);
2603
0
          zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2604
0
        }
2605
0
        if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2606
0
          zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", ZSTR_VAL(precedences[i]->trait_method.method_name), ZSTR_VAL(exclude_ce->name));
2607
0
        }
2608
2609
        /* make sure that the trait method is not from a class mentioned in
2610
         exclude_from_classes, for consistency */
2611
0
        if (trait == exclude_ce) {
2612
0
          zend_error_noreturn(E_COMPILE_ERROR,
2613
0
                 "Inconsistent insteadof definition. "
2614
0
                 "The method %s is to be used from %s, but %s is also on the exclude list",
2615
0
                 ZSTR_VAL(cur_method_ref->method_name),
2616
0
                 ZSTR_VAL(trait->name),
2617
0
                 ZSTR_VAL(trait->name));
2618
0
        }
2619
0
      }
2620
0
      zend_string_release_ex(lcname, 0);
2621
0
      i++;
2622
0
    }
2623
0
    ce->trait_precedences = precedences;
2624
0
  }
2625
2626
0
  if (ce->trait_aliases) {
2627
0
    i = 0;
2628
0
    while (ce->trait_aliases[i]) {
2629
0
      i++;
2630
0
    }
2631
0
    aliases = ecalloc(i, sizeof(zend_class_entry*));
2632
0
    i = 0;
2633
0
    while (ce->trait_aliases[i]) {
2634
0
      const zend_trait_alias *cur_alias = ce->trait_aliases[i];
2635
0
      cur_method_ref = &ce->trait_aliases[i]->trait_method;
2636
0
      lcname = zend_string_tolower(cur_method_ref->method_name);
2637
0
      if (cur_method_ref->class_name) {
2638
        /* For all aliases with an explicit class name, resolve the class now. */
2639
0
        lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2640
0
        trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2641
0
        zend_string_release_ex(lc_trait_name, 0);
2642
0
        if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2643
0
          zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2644
0
        }
2645
0
        zend_check_trait_usage(ce, trait, traits);
2646
0
        aliases[i] = trait;
2647
2648
        /* And, ensure that the referenced method is resolvable, too. */
2649
0
        if (!zend_hash_exists(&trait->function_table, lcname)) {
2650
0
          zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name));
2651
0
        }
2652
0
      } else {
2653
        /* Find out which trait this method refers to. */
2654
0
        trait = NULL;
2655
0
        for (j = 0; j < ce->num_traits; j++) {
2656
0
          if (traits[j]) {
2657
0
            if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2658
0
              if (!trait) {
2659
0
                trait = traits[j];
2660
0
                continue;
2661
0
              }
2662
2663
0
              zend_error_noreturn(E_COMPILE_ERROR,
2664
0
                "An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
2665
0
                ZSTR_VAL(cur_method_ref->method_name),
2666
0
                ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2667
0
                ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2668
0
                ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2669
0
            }
2670
0
          }
2671
0
        }
2672
2673
        /* Non-absolute method reference refers to method that does not exist. */
2674
0
        if (!trait) {
2675
0
          if (cur_alias->alias) {
2676
0
            zend_error_noreturn(E_COMPILE_ERROR,
2677
0
              "An alias (%s) was defined for method %s(), but this method does not exist",
2678
0
              ZSTR_VAL(cur_alias->alias),
2679
0
              ZSTR_VAL(cur_alias->trait_method.method_name));
2680
0
          } else {
2681
0
            zend_error_noreturn(E_COMPILE_ERROR,
2682
0
              "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2683
0
              ZSTR_VAL(cur_alias->trait_method.method_name));
2684
0
          }
2685
0
        }
2686
2687
0
        aliases[i] = trait;
2688
0
      }
2689
0
      zend_string_release_ex(lcname, 0);
2690
0
      i++;
2691
0
    }
2692
0
  }
2693
2694
0
  *exclude_tables_ptr = exclude_tables;
2695
0
  *aliases_ptr = aliases;
2696
0
}
2697
/* }}} */
2698
2699
static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases, bool verify_abstract, bool *contains_abstract_methods) /* {{{ */
2700
0
{
2701
0
  uint32_t i;
2702
0
  zend_string *key;
2703
0
  zend_function *fn;
2704
2705
0
  if (exclude_tables) {
2706
0
    for (i = 0; i < ce->num_traits; i++) {
2707
0
      if (traits[i]) {
2708
        /* copies functions, applies defined aliasing, and excludes unused trait methods */
2709
0
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2710
0
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2711
0
          *contains_abstract_methods |= is_abstract;
2712
0
          if (verify_abstract != is_abstract) {
2713
0
            continue;
2714
0
          }
2715
0
          zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2716
0
        } ZEND_HASH_FOREACH_END();
2717
2718
0
        if (exclude_tables[i]) {
2719
0
          zend_hash_destroy(exclude_tables[i]);
2720
0
          FREE_HASHTABLE(exclude_tables[i]);
2721
0
          exclude_tables[i] = NULL;
2722
0
        }
2723
0
      }
2724
0
    }
2725
0
  } else {
2726
0
    for (i = 0; i < ce->num_traits; i++) {
2727
0
      if (traits[i]) {
2728
0
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2729
0
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2730
0
          *contains_abstract_methods |= is_abstract;
2731
0
          if (verify_abstract != is_abstract) {
2732
0
            continue;
2733
0
          }
2734
0
          zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2735
0
        } ZEND_HASH_FOREACH_END();
2736
0
      }
2737
0
    }
2738
0
  }
2739
0
}
2740
/* }}} */
2741
2742
static const zend_class_entry* find_first_constant_definition(const zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *constant_name, const zend_class_entry *colliding_ce) /* {{{ */
2743
0
{
2744
  /* This function is used to show the place of the existing conflicting
2745
   * definition in error messages when conflicts occur. Since trait constants
2746
   * are flattened into the constants table of the composing class, and thus
2747
   * we lose information about which constant was defined in which trait, a
2748
   * process like this is needed to find the location of the first definition
2749
   * of the constant from traits.
2750
   */
2751
0
  if (colliding_ce == ce) {
2752
0
    for (size_t i = 0; i < current_trait; i++) {
2753
0
      if (traits[i]
2754
0
        && zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2755
0
        return traits[i];
2756
0
      }
2757
0
    }
2758
0
  }
2759
  /* Traits don't have it, then the composing class (or trait) itself has it. */
2760
0
  return colliding_ce;
2761
0
}
2762
/* }}} */
2763
2764
static void emit_incompatible_trait_constant_error(
2765
  const zend_class_entry *ce, const zend_class_constant *existing_constant, const zend_class_constant *trait_constant, zend_string *name,
2766
  zend_class_entry **traits, size_t current_trait
2767
0
) {
2768
0
  zend_error_noreturn(E_COMPILE_ERROR,
2769
0
    "%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2770
0
    ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2771
0
    ZSTR_VAL(trait_constant->ce->name),
2772
0
    ZSTR_VAL(name),
2773
0
    ZSTR_VAL(ce->name)
2774
0
  );
2775
0
}
2776
2777
static bool do_trait_constant_check(
2778
  zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait
2779
0
) {
2780
0
  uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2781
2782
0
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2783
0
  if (zv == NULL) {
2784
    /* No existing constant of the same name, so this one can be added */
2785
0
    return true;
2786
0
  }
2787
2788
0
  zend_class_constant *existing_constant = Z_PTR_P(zv);
2789
2790
0
  if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2791
0
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2792
0
    return false;
2793
0
  }
2794
2795
0
  if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) {
2796
0
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2797
0
    return false;
2798
0
  } else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2799
0
    inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2800
0
    inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2801
0
    if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
2802
0
      emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2803
0
      return false;
2804
0
    }
2805
0
  }
2806
2807
0
  if (!check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &existing_constant->value)) {
2808
    /* There is an existing constant of the same name, and it conflicts with the new one, so let's throw a fatal error */
2809
0
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2810
0
    return false;
2811
0
  }
2812
2813
  /* There is an existing constant which is compatible with the new one, so no need to add it */
2814
0
  return false;
2815
0
}
2816
2817
static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2818
0
{
2819
0
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2820
0
    zend_string *constant_name;
2821
0
    zend_class_constant *constant;
2822
2823
0
    if (!traits[i]) {
2824
0
      continue;
2825
0
    }
2826
2827
0
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2828
0
      if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2829
0
        zend_class_constant *ct = NULL;
2830
2831
0
        ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2832
0
        memcpy(ct, constant, sizeof(zend_class_constant));
2833
0
        constant = ct;
2834
2835
0
        if (Z_TYPE(constant->value) == IS_CONSTANT_AST) {
2836
0
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2837
0
          ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2838
0
        }
2839
2840
        /* Unlike interface implementations and class inheritances,
2841
         * access control of the trait constants is done by the scope
2842
         * of the composing class. So let's replace the ce here.
2843
         */
2844
0
        constant->ce = ce;
2845
2846
0
        Z_TRY_ADDREF(constant->value);
2847
0
        constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2848
0
        if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2849
0
          GC_ADDREF(constant->attributes);
2850
0
        }
2851
2852
0
        zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2853
0
      }
2854
0
    } ZEND_HASH_FOREACH_END();
2855
0
  }
2856
0
}
2857
/* }}} */
2858
2859
static const zend_class_entry* find_first_property_definition(const zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *prop_name, const zend_class_entry *colliding_ce) /* {{{ */
2860
0
{
2861
0
  if (colliding_ce == ce) {
2862
0
    for (size_t i = 0; i < current_trait; i++) {
2863
0
      if (traits[i]
2864
0
       && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2865
0
        return traits[i];
2866
0
      }
2867
0
    }
2868
0
  }
2869
2870
0
  return colliding_ce;
2871
0
}
2872
/* }}} */
2873
2874
static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2875
0
{
2876
0
  zend_property_info *property_info;
2877
0
  const zend_property_info *colliding_prop;
2878
0
  zend_string* prop_name;
2879
0
  zval* prop_value;
2880
2881
  /* In the following steps the properties are inserted into the property table
2882
   * for that, a very strict approach is applied:
2883
   * - check for compatibility, if not compatible with any property in class -> fatal
2884
   * - if compatible, then strict notice
2885
   */
2886
0
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2887
0
    if (!traits[i]) {
2888
0
      continue;
2889
0
    }
2890
0
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2891
0
      uint32_t flags = property_info->flags;
2892
2893
      /* next: check for conflicts with current class */
2894
0
      if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2895
0
        if ((colliding_prop->flags & ZEND_ACC_PRIVATE) && colliding_prop->ce != ce) {
2896
0
          zend_hash_del(&ce->properties_info, prop_name);
2897
0
          flags |= ZEND_ACC_CHANGED;
2898
0
        } else {
2899
0
          bool is_compatible = false;
2900
0
          uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2901
2902
0
          if (colliding_prop->hooks || property_info->hooks) {
2903
0
            zend_error_noreturn(E_COMPILE_ERROR,
2904
0
              "%s and %s define the same hooked property ($%s) in the composition of %s. Conflict resolution between hooked properties is currently not supported. Class was composed",
2905
0
              ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2906
0
              ZSTR_VAL(property_info->ce->name),
2907
0
              ZSTR_VAL(prop_name),
2908
0
              ZSTR_VAL(ce->name));
2909
0
          }
2910
2911
0
          if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2912
0
            verify_property_type_compatibility(property_info, colliding_prop, PROP_INVARIANT, false, false) == INHERITANCE_SUCCESS
2913
0
          ) {
2914
            /* the flags are identical, thus, the properties may be compatible */
2915
0
            zval *op1, *op2;
2916
2917
0
            if (flags & ZEND_ACC_STATIC) {
2918
0
              op1 = &ce->default_static_members_table[colliding_prop->offset];
2919
0
              op2 = &traits[i]->default_static_members_table[property_info->offset];
2920
0
              ZVAL_DEINDIRECT(op1);
2921
0
              ZVAL_DEINDIRECT(op2);
2922
0
            } else {
2923
0
              op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2924
0
              op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2925
0
            }
2926
0
            is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2927
0
          }
2928
2929
0
          if (!is_compatible) {
2930
0
            zend_error_noreturn(E_COMPILE_ERROR,
2931
0
                "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2932
0
                ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2933
0
                ZSTR_VAL(property_info->ce->name),
2934
0
                ZSTR_VAL(prop_name),
2935
0
                ZSTR_VAL(ce->name));
2936
0
          }
2937
0
          if (!(flags & ZEND_ACC_STATIC)) {
2938
0
            continue;
2939
0
          }
2940
0
        }
2941
0
      }
2942
2943
0
      if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS) && !(property_info->flags & ZEND_ACC_READONLY)) {
2944
0
        zend_error_noreturn(E_COMPILE_ERROR,
2945
0
          "Readonly class %s cannot use trait with a non-readonly property %s::$%s",
2946
0
          ZSTR_VAL(ce->name),
2947
0
          ZSTR_VAL(property_info->ce->name),
2948
0
          ZSTR_VAL(prop_name)
2949
0
        );
2950
0
      }
2951
2952
      /* property not found, so lets add it */
2953
0
      zval tmp_prop_value;
2954
0
      if (!(flags & ZEND_ACC_VIRTUAL)) {
2955
0
        if (flags & ZEND_ACC_STATIC) {
2956
0
          prop_value = &traits[i]->default_static_members_table[property_info->offset];
2957
0
          ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2958
0
        } else {
2959
0
          prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2960
0
        }
2961
0
        Z_TRY_ADDREF_P(prop_value);
2962
0
      } else {
2963
0
        prop_value = &tmp_prop_value;
2964
0
        ZVAL_UNDEF(&tmp_prop_value);
2965
0
      }
2966
2967
0
      zend_string *doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2968
2969
0
      zend_type type = property_info->type;
2970
      /* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2971
0
      zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2972
0
      zend_property_info *new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2973
2974
0
      if (property_info->attributes) {
2975
0
        new_prop->attributes = property_info->attributes;
2976
2977
0
        if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2978
0
          GC_ADDREF(new_prop->attributes);
2979
0
        }
2980
0
      }
2981
0
      if (property_info->hooks) {
2982
0
        zend_function **hooks = new_prop->hooks =
2983
0
          zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2984
0
        memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2985
0
        for (uint32_t j = 0; j < ZEND_PROPERTY_HOOK_COUNT; j++) {
2986
0
          if (hooks[j]) {
2987
0
            zend_function *old_fn = hooks[j];
2988
2989
            /* Hooks are not yet supported for internal properties. */
2990
0
            ZEND_ASSERT(ZEND_USER_CODE(old_fn->type));
2991
2992
            /* Copy the function, because we need to adjust the scope. */
2993
0
            zend_function *new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2994
0
            memcpy(new_fn, old_fn, sizeof(zend_op_array));
2995
0
            new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2996
0
            new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2997
0
            new_fn->common.prop_info = new_prop;
2998
0
            function_add_ref(new_fn);
2999
3000
0
            zend_fixup_trait_method(new_fn, ce);
3001
3002
0
            hooks[j] = new_fn;
3003
0
          }
3004
0
        }
3005
0
        ce->num_hooked_props++;
3006
0
      }
3007
0
    } ZEND_HASH_FOREACH_END();
3008
0
  }
3009
0
}
3010
/* }}} */
3011
3012
97
#define MAX_ABSTRACT_INFO_CNT 3
3013
#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
3014
#define DISPLAY_ABSTRACT_FN(idx) \
3015
120
  ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
3016
120
  ai.afn[idx] ? "::" : "", \
3017
120
  ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
3018
120
  ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
3019
3020
typedef struct _zend_abstract_info {
3021
  const zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
3022
  int cnt;
3023
} zend_abstract_info;
3024
3025
static void zend_verify_abstract_class_function(const zend_function *fn, zend_abstract_info *ai) /* {{{ */
3026
57
{
3027
57
  if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
3028
55
    ai->afn[ai->cnt] = fn;
3029
55
  }
3030
57
  ai->cnt++;
3031
57
}
3032
/* }}} */
3033
3034
void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
3035
130
{
3036
130
  const zend_function *func;
3037
130
  zend_abstract_info ai;
3038
130
  bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
3039
130
  bool can_be_abstract = (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_ANON_CLASS)) == 0;
3040
130
  memset(&ai, 0, sizeof(ai));
3041
3042
294
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
3043
294
    if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
3044
      /* If the class is explicitly abstract, we only check private abstract methods,
3045
       * because only they must be declared in the same class. */
3046
6
      if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
3047
6
        zend_verify_abstract_class_function(func, &ai);
3048
6
      }
3049
6
    }
3050
294
  } ZEND_HASH_FOREACH_END();
3051
3052
130
  if (!is_explicit_abstract) {
3053
130
    const zend_property_info *prop_info;
3054
428
    ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
3055
428
      if (prop_info->hooks) {
3056
420
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3057
280
          const zend_function *fn = prop_info->hooks[i];
3058
280
          if (fn && (fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3059
51
            zend_verify_abstract_class_function(fn, &ai);
3060
51
          }
3061
280
        }
3062
140
      }
3063
428
    } ZEND_HASH_FOREACH_END();
3064
130
  }
3065
3066
130
  if (ai.cnt) {
3067
40
    if (!is_explicit_abstract && can_be_abstract) {
3068
40
      zend_error_noreturn(E_ERROR,
3069
40
        "%s %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3070
40
        zend_get_object_type_uc(ce),
3071
40
        ZSTR_VAL(ce->name), ai.cnt,
3072
40
        ai.cnt > 1 ? "s" : "",
3073
40
        ai.cnt > 1 ? "s" : "",
3074
40
        DISPLAY_ABSTRACT_FN(0),
3075
40
        DISPLAY_ABSTRACT_FN(1),
3076
40
        DISPLAY_ABSTRACT_FN(2)
3077
40
      );
3078
40
    } else {
3079
0
      zend_error_noreturn(E_ERROR,
3080
0
        "%s %s must implement %d abstract method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3081
0
        zend_get_object_type_uc(ce),
3082
0
        ZSTR_VAL(ce->name), ai.cnt,
3083
0
        ai.cnt > 1 ? "s" : "",
3084
0
        DISPLAY_ABSTRACT_FN(0),
3085
0
        DISPLAY_ABSTRACT_FN(1),
3086
0
        DISPLAY_ABSTRACT_FN(2)
3087
0
      );
3088
0
    }
3089
90
  } else {
3090
    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
3091
90
    ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3092
90
  }
3093
130
}
3094
/* }}} */
3095
3096
typedef struct {
3097
  enum {
3098
    OBLIGATION_DEPENDENCY,
3099
    OBLIGATION_COMPATIBILITY,
3100
    OBLIGATION_PROPERTY_COMPATIBILITY,
3101
    OBLIGATION_CLASS_CONSTANT_COMPATIBILITY,
3102
    OBLIGATION_PROPERTY_HOOK,
3103
  } type;
3104
  union {
3105
    zend_class_entry *dependency_ce;
3106
    struct {
3107
      /* Traits may use temporary on-stack functions during inheritance checks,
3108
       * so use copies of functions here as well. */
3109
      zend_function parent_fn;
3110
      zend_function child_fn;
3111
      zend_class_entry *child_scope;
3112
      zend_class_entry *parent_scope;
3113
    };
3114
    struct {
3115
      const zend_property_info *parent_prop;
3116
      const zend_property_info *child_prop;
3117
      prop_variance variance;
3118
    };
3119
    struct {
3120
      const zend_string *const_name;
3121
      const zend_class_constant *parent_const;
3122
      const zend_class_constant *child_const;
3123
    };
3124
    struct {
3125
      const zend_property_info *hooked_prop;
3126
      const zend_function *hook_func;
3127
    };
3128
  };
3129
} variance_obligation;
3130
3131
1
static void variance_obligation_dtor(zval *zv) {
3132
1
  efree(Z_PTR_P(zv));
3133
1
}
3134
3135
1
static void variance_obligation_ht_dtor(zval *zv) {
3136
1
  zend_hash_destroy(Z_PTR_P(zv));
3137
1
  FREE_HASHTABLE(Z_PTR_P(zv));
3138
1
}
3139
3140
1
static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
3141
1
  HashTable *ht;
3142
1
  zend_ulong key;
3143
1
  if (!CG(delayed_variance_obligations)) {
3144
1
    ALLOC_HASHTABLE(CG(delayed_variance_obligations));
3145
1
    zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
3146
1
  }
3147
3148
1
  key = (zend_ulong) (uintptr_t) ce;
3149
1
  ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
3150
1
  if (ht) {
3151
0
    return ht;
3152
0
  }
3153
3154
1
  ALLOC_HASHTABLE(ht);
3155
1
  zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
3156
1
  zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
3157
1
  ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
3158
1
  return ht;
3159
1
}
3160
3161
0
static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
3162
0
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3163
0
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3164
0
  obligation->type = OBLIGATION_DEPENDENCY;
3165
0
  obligation->dependency_ce = dependency_ce;
3166
0
  zend_hash_next_index_insert_ptr(obligations, obligation);
3167
0
}
3168
3169
static void add_compatibility_obligation(
3170
    zend_class_entry *ce,
3171
    const zend_function *child_fn, zend_class_entry *child_scope,
3172
1
    const zend_function *parent_fn, zend_class_entry *parent_scope) {
3173
1
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3174
1
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3175
1
  obligation->type = OBLIGATION_COMPATIBILITY;
3176
  /* Copy functions, because they may be stack-allocated in the case of traits. */
3177
1
  if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3178
0
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
3179
1
  } else {
3180
1
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
3181
1
  }
3182
1
  if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3183
0
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
3184
1
  } else {
3185
1
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
3186
1
  }
3187
1
  obligation->child_scope = child_scope;
3188
1
  obligation->parent_scope = parent_scope;
3189
1
  zend_hash_next_index_insert_ptr(obligations, obligation);
3190
1
}
3191
3192
static void add_property_compatibility_obligation(
3193
    zend_class_entry *ce, const zend_property_info *child_prop,
3194
0
    const zend_property_info *parent_prop, prop_variance variance) {
3195
0
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3196
0
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3197
0
  obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
3198
0
  obligation->child_prop = child_prop;
3199
0
  obligation->parent_prop = parent_prop;
3200
0
  obligation->variance = variance;
3201
0
  zend_hash_next_index_insert_ptr(obligations, obligation);
3202
0
}
3203
3204
static void add_class_constant_compatibility_obligation(
3205
    zend_class_entry *ce, const zend_class_constant *child_const,
3206
0
    const zend_class_constant *parent_const, const zend_string *const_name) {
3207
0
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3208
0
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3209
0
  obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY;
3210
0
  obligation->const_name = const_name;
3211
0
  obligation->child_const = child_const;
3212
0
  obligation->parent_const = parent_const;
3213
0
  zend_hash_next_index_insert_ptr(obligations, obligation);
3214
0
}
3215
3216
static void add_property_hook_obligation(
3217
0
    zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func) {
3218
0
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3219
0
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3220
0
  obligation->type = OBLIGATION_PROPERTY_HOOK;
3221
0
  obligation->hooked_prop = hooked_prop;
3222
0
  obligation->hook_func = hook_func;
3223
0
  zend_hash_next_index_insert_ptr(obligations, obligation);
3224
0
}
3225
3226
static void resolve_delayed_variance_obligations(zend_class_entry *ce);
3227
3228
0
static void check_variance_obligation(const variance_obligation *obligation) {
3229
0
  if (obligation->type == OBLIGATION_DEPENDENCY) {
3230
0
    zend_class_entry *dependency_ce = obligation->dependency_ce;
3231
0
    if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3232
0
      zend_class_entry *orig_linking_class = CG(current_linking_class);
3233
3234
0
      CG(current_linking_class) =
3235
0
        (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
3236
0
      resolve_delayed_variance_obligations(dependency_ce);
3237
0
      CG(current_linking_class) = orig_linking_class;
3238
0
    }
3239
0
  } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
3240
0
    inheritance_status status = zend_do_perform_implementation_check(
3241
0
      &obligation->child_fn, obligation->child_scope,
3242
0
      &obligation->parent_fn, obligation->parent_scope);
3243
0
    if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3244
0
      emit_incompatible_method_error(
3245
0
        &obligation->child_fn, obligation->child_scope,
3246
0
        &obligation->parent_fn, obligation->parent_scope, status);
3247
0
    }
3248
    /* Either the compatibility check was successful or only threw a warning. */
3249
0
  } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
3250
0
    verify_property_type_compatibility(obligation->parent_prop, obligation->child_prop, obligation->variance, true, true);
3251
0
  } else if (obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY) {
3252
0
    inheritance_status status =
3253
0
    class_constant_types_compatible(obligation->parent_const, obligation->child_const);
3254
0
    if (status != INHERITANCE_SUCCESS) {
3255
0
      emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name);
3256
0
    }
3257
0
  } else if (obligation->type == OBLIGATION_PROPERTY_HOOK) {
3258
0
    inheritance_status status = zend_verify_property_hook_variance(obligation->hooked_prop, obligation->hook_func);
3259
0
    if (status != INHERITANCE_SUCCESS) {
3260
0
      zend_hooked_property_variance_error(obligation->hooked_prop);
3261
0
    }
3262
0
  } else {
3263
0
    ZEND_UNREACHABLE();
3264
0
  }
3265
0
}
3266
3267
0
static void load_delayed_classes(const zend_class_entry *ce) {
3268
0
  HashTable *delayed_autoloads = CG(delayed_autoloads);
3269
0
  if (!delayed_autoloads) {
3270
0
    return;
3271
0
  }
3272
3273
  /* Autoloading can trigger linking of another class, which may register new delayed autoloads.
3274
   * For that reason, this code uses a loop that pops and loads the first element of the HT. If
3275
   * this triggers linking, then the remaining classes may get loaded when linking the newly
3276
   * loaded class. This is important, as otherwise necessary dependencies may not be available
3277
   * if the new class is lower in the hierarchy than the current one. */
3278
0
  HashPosition pos = 0;
3279
0
  zend_string *name;
3280
0
  zend_ulong idx;
3281
0
  while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
3282
0
      != HASH_KEY_NON_EXISTENT) {
3283
0
    zend_string_addref(name);
3284
0
    zend_hash_del(delayed_autoloads, name);
3285
0
    zend_lookup_class(name);
3286
0
    zend_string_release(name);
3287
0
    if (EG(exception)) {
3288
0
      zend_exception_uncaught_error(
3289
0
        "During inheritance of %s, while autoloading %s",
3290
0
        ZSTR_VAL(ce->name), ZSTR_VAL(name));
3291
0
    }
3292
0
  }
3293
0
}
3294
3295
0
static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
3296
0
  HashTable *all_obligations = CG(delayed_variance_obligations);
3297
0
  zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
3298
3299
0
  ZEND_ASSERT(all_obligations != NULL);
3300
0
  const HashTable *obligations = zend_hash_index_find_ptr(all_obligations, num_key);
3301
0
  ZEND_ASSERT(obligations != NULL);
3302
3303
0
  variance_obligation *obligation;
3304
0
  ZEND_HASH_FOREACH_PTR(obligations, obligation) {
3305
0
    check_variance_obligation(obligation);
3306
0
  } ZEND_HASH_FOREACH_END();
3307
3308
0
  zend_inheritance_check_override(ce);
3309
3310
0
  ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
3311
0
  ce->ce_flags |= ZEND_ACC_LINKED;
3312
0
  zend_hash_index_del(all_obligations, num_key);
3313
0
}
3314
3315
0
static void check_unrecoverable_load_failure(const zend_class_entry *ce) {
3316
  /* If this class has been used while unlinked through a variance obligation, it is not legal
3317
   * to remove the class from the class table and throw an exception, because there is already
3318
   * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
3319
   * a fatal error, as would happen if we did not allow exceptions in the first place. */
3320
0
  if (CG(unlinked_uses)
3321
0
      && zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t)ce) == SUCCESS) {
3322
0
    zend_exception_uncaught_error(
3323
0
      "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
3324
0
  }
3325
0
}
3326
3327
0
#define zend_update_inherited_handler(handler) do { \
3328
0
    if (ce->handler == (zend_function*)op_array) { \
3329
0
      ce->handler = (zend_function*)new_op_array; \
3330
0
    } \
3331
0
  } while (0)
3332
3333
static zend_op_array *zend_lazy_method_load(
3334
0
    const zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3335
0
  ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3336
0
  ZEND_ASSERT(op_array->scope == pce);
3337
0
  ZEND_ASSERT(op_array->prototype == NULL);
3338
0
  zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3339
0
  memcpy(new_op_array, op_array, sizeof(zend_op_array));
3340
0
  new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3341
0
  new_op_array->scope = ce;
3342
0
  ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3343
0
  ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3344
3345
0
  return new_op_array;
3346
0
}
3347
3348
static zend_class_entry *zend_lazy_class_load(const zend_class_entry *pce)
3349
0
{
3350
0
  zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3351
3352
0
  memcpy(ce, pce, sizeof(zend_class_entry));
3353
0
  ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3354
0
  ce->refcount = 1;
3355
0
  ce->inheritance_cache = NULL;
3356
0
  if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3357
0
    ZEND_MAP_PTR_NEW(ce->mutable_data);
3358
0
  } else {
3359
0
    ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3360
0
  }
3361
3362
  /* properties */
3363
0
  if (ce->default_properties_table) {
3364
0
    zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3365
0
    zval *src = ce->default_properties_table;
3366
0
    const zval *end = src + ce->default_properties_count;
3367
3368
0
    ce->default_properties_table = dst;
3369
0
    for (; src != end; src++, dst++) {
3370
0
      ZVAL_COPY_VALUE_PROP(dst, src);
3371
0
    }
3372
0
  }
3373
3374
  /* methods */
3375
0
  ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3376
0
  if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3377
0
    Bucket *p = emalloc(HT_SIZE(&ce->function_table));
3378
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3379
0
    HT_SET_DATA_ADDR(&ce->function_table, p);
3380
0
    p = ce->function_table.arData;
3381
0
    const Bucket *end = p + ce->function_table.nNumUsed;
3382
0
    for (; p != end; p++) {
3383
0
      zend_op_array *op_array = Z_PTR(p->val);
3384
0
      zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3385
3386
0
      zend_update_inherited_handler(constructor);
3387
0
      zend_update_inherited_handler(destructor);
3388
0
      zend_update_inherited_handler(clone);
3389
0
      zend_update_inherited_handler(__get);
3390
0
      zend_update_inherited_handler(__set);
3391
0
      zend_update_inherited_handler(__call);
3392
0
      zend_update_inherited_handler(__isset);
3393
0
      zend_update_inherited_handler(__unset);
3394
0
      zend_update_inherited_handler(__tostring);
3395
0
      zend_update_inherited_handler(__callstatic);
3396
0
      zend_update_inherited_handler(__debugInfo);
3397
0
      zend_update_inherited_handler(__serialize);
3398
0
      zend_update_inherited_handler(__unserialize);
3399
0
    }
3400
0
  }
3401
3402
  /* static members */
3403
0
  if (ce->default_static_members_table) {
3404
0
    zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
3405
0
    zval *src = ce->default_static_members_table;
3406
0
    const zval *end = src + ce->default_static_members_count;
3407
3408
0
    ce->default_static_members_table = dst;
3409
0
    for (; src != end; src++, dst++) {
3410
0
      ZVAL_COPY_VALUE(dst, src);
3411
0
    }
3412
0
  }
3413
0
  ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3414
3415
  /* properties_info */
3416
0
  if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3417
0
    Bucket *p = emalloc(HT_SIZE(&ce->properties_info));
3418
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3419
0
    HT_SET_DATA_ADDR(&ce->properties_info, p);
3420
0
    p = ce->properties_info.arData;
3421
0
    const Bucket *end = p + ce->properties_info.nNumUsed;
3422
0
    for (; p != end; p++) {
3423
0
      zend_property_info *new_prop_info;
3424
3425
0
      const zend_property_info *prop_info = Z_PTR(p->val);
3426
0
      ZEND_ASSERT(prop_info->ce == pce);
3427
0
      ZEND_ASSERT(prop_info->prototype == prop_info);
3428
0
      new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3429
0
      Z_PTR(p->val) = new_prop_info;
3430
0
      memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3431
0
      new_prop_info->ce = ce;
3432
0
      new_prop_info->prototype = new_prop_info;
3433
      /* Deep copy the type information */
3434
0
      zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3435
0
      if (new_prop_info->hooks) {
3436
0
        new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3437
0
        memcpy(new_prop_info->hooks, prop_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3438
0
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3439
0
          if (new_prop_info->hooks[i]) {
3440
0
            zend_op_array *hook = zend_lazy_method_load((zend_op_array *) new_prop_info->hooks[i], ce, pce);
3441
0
            ZEND_ASSERT(hook->prop_info == prop_info);
3442
0
            hook->prop_info = new_prop_info;
3443
0
            new_prop_info->ce = ce;
3444
0
            new_prop_info->hooks[i] = (zend_function *) hook;
3445
0
          }
3446
0
        }
3447
0
      }
3448
0
    }
3449
0
  }
3450
3451
  /* constants table */
3452
0
  if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3453
0
    Bucket *p = emalloc(HT_SIZE(&ce->constants_table));
3454
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3455
0
    HT_SET_DATA_ADDR(&ce->constants_table, p);
3456
0
    p = ce->constants_table.arData;
3457
0
    const Bucket *end = p + ce->constants_table.nNumUsed;
3458
0
    for (; p != end; p++) {
3459
0
      zend_class_constant *new_c;
3460
3461
0
      const zend_class_constant *c = Z_PTR(p->val);
3462
0
      ZEND_ASSERT(c->ce == pce);
3463
0
      new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3464
0
      Z_PTR(p->val) = new_c;
3465
0
      memcpy(new_c, c, sizeof(zend_class_constant));
3466
0
      new_c->ce = ce;
3467
0
    }
3468
0
  }
3469
3470
0
  return ce;
3471
0
}
3472
3473
#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
3474
5.51k
# define UPDATE_IS_CACHEABLE(ce) do { \
3475
5.51k
      if ((ce)->type == ZEND_USER_CLASS) { \
3476
4.61k
        is_cacheable &= (ce)->ce_flags; \
3477
4.61k
      } \
3478
5.51k
    } while (0)
3479
#else
3480
// TODO: ASLR may cause different addresses in different workers ???
3481
# define UPDATE_IS_CACHEABLE(ce) do { \
3482
      is_cacheable &= (ce)->ce_flags; \
3483
    } while (0)
3484
#endif
3485
3486
ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, const zend_string *key) /* {{{ */
3487
0
{
3488
  /* Load parent/interface dependencies first, so we can still gracefully abort linking
3489
   * with an exception and remove the class from the class table. This is only possible
3490
   * if no variance obligations on the current class have been added during autoloading. */
3491
0
  zend_class_entry *parent = NULL;
3492
0
  zend_class_entry **traits_and_interfaces = NULL;
3493
0
  zend_class_entry *proto = NULL;
3494
0
  zend_class_entry *orig_linking_class;
3495
0
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3496
0
  uint32_t i, j;
3497
0
  zval *zv;
3498
0
  ALLOCA_FLAG(use_heap)
3499
3500
0
  SET_ALLOCA_FLAG(use_heap);
3501
0
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3502
3503
0
  if (ce->parent_name) {
3504
0
    parent = zend_fetch_class_by_name(
3505
0
      ce->parent_name, lc_parent_name,
3506
0
      ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3507
0
    if (!parent) {
3508
0
      check_unrecoverable_load_failure(ce);
3509
0
      return NULL;
3510
0
    }
3511
0
    UPDATE_IS_CACHEABLE(parent);
3512
0
  }
3513
3514
0
  if (ce->num_traits || ce->num_interfaces) {
3515
0
    traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3516
3517
0
    for (i = 0; i < ce->num_traits; i++) {
3518
0
      zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3519
0
        ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
3520
0
      if (UNEXPECTED(trait == NULL)) {
3521
0
        free_alloca(traits_and_interfaces, use_heap);
3522
0
        return NULL;
3523
0
      }
3524
0
      if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
3525
0
        zend_throw_error(NULL, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
3526
0
        free_alloca(traits_and_interfaces, use_heap);
3527
0
        return NULL;
3528
0
      }
3529
0
      if (UNEXPECTED(trait->ce_flags & ZEND_ACC_DEPRECATED)) {
3530
0
        zend_use_of_deprecated_trait(trait, ce->name);
3531
0
        if (UNEXPECTED(EG(exception))) {
3532
0
          free_alloca(traits_and_interfaces, use_heap);
3533
0
          return NULL;
3534
0
        }
3535
0
      }
3536
0
      for (j = 0; j < i; j++) {
3537
0
        if (traits_and_interfaces[j] == trait) {
3538
          /* skip duplications */
3539
0
          trait = NULL;
3540
0
          break;
3541
0
        }
3542
0
      }
3543
0
      traits_and_interfaces[i] = trait;
3544
0
      if (trait) {
3545
0
        UPDATE_IS_CACHEABLE(trait);
3546
0
      }
3547
0
    }
3548
0
  }
3549
3550
0
  if (ce->num_interfaces) {
3551
0
    for (i = 0; i < ce->num_interfaces; i++) {
3552
0
      zend_class_entry *iface = zend_fetch_class_by_name(
3553
0
        ce->interface_names[i].name, ce->interface_names[i].lc_name,
3554
0
        ZEND_FETCH_CLASS_INTERFACE |
3555
0
        ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3556
0
      if (!iface) {
3557
0
        check_unrecoverable_load_failure(ce);
3558
0
        free_alloca(traits_and_interfaces, use_heap);
3559
0
        return NULL;
3560
0
      }
3561
0
      traits_and_interfaces[ce->num_traits + i] = iface;
3562
0
      if (iface) {
3563
0
        UPDATE_IS_CACHEABLE(iface);
3564
0
      }
3565
0
    }
3566
0
  }
3567
3568
0
#ifndef ZEND_WIN32
3569
0
  if (ce->ce_flags & ZEND_ACC_ENUM) {
3570
    /* We will add internal methods. */
3571
0
    is_cacheable = false;
3572
0
  }
3573
0
#endif
3574
3575
0
  if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3576
0
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3577
0
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3578
0
      if (ret) {
3579
0
        if (traits_and_interfaces) {
3580
0
          free_alloca(traits_and_interfaces, use_heap);
3581
0
        }
3582
0
        zv = zend_hash_find_known_hash(CG(class_table), key);
3583
0
        Z_CE_P(zv) = ret;
3584
0
        return ret;
3585
0
      }
3586
0
    } else {
3587
0
      is_cacheable = 0;
3588
0
    }
3589
0
    proto = ce;
3590
0
  }
3591
3592
  /* Delay and record warnings (such as deprecations) thrown during
3593
   * inheritance, so they will be recorded in the inheritance cache.
3594
   * Warnings must be delayed in all cases so that we get a consistent
3595
   * behavior regardless of cacheability. */
3596
0
  bool orig_record_errors = EG(record_errors);
3597
0
  if (!orig_record_errors) {
3598
0
    zend_begin_record_errors();
3599
0
  }
3600
3601
0
  zend_try {
3602
0
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3603
      /* Lazy class loading */
3604
0
      ce = zend_lazy_class_load(ce);
3605
0
      zv = zend_hash_find_known_hash(CG(class_table), key);
3606
0
      Z_CE_P(zv) = ce;
3607
0
    } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3608
      /* Lazy class loading */
3609
0
      ce = zend_lazy_class_load(ce);
3610
0
      ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3611
0
      zv = zend_hash_find_known_hash(CG(class_table), key);
3612
0
      Z_CE_P(zv) = ce;
3613
0
    }
3614
3615
0
    if (CG(unlinked_uses)) {
3616
0
      zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3617
0
    }
3618
3619
0
    orig_linking_class = CG(current_linking_class);
3620
0
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3621
3622
0
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3623
      /* Only register builtin enum methods during inheritance to avoid persisting them in
3624
       * opcache. */
3625
0
      zend_enum_register_funcs(ce);
3626
0
    }
3627
3628
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3629
    zend_link_hooked_object_iter(ce);
3630
#endif
3631
3632
0
    HashTable **trait_exclude_tables;
3633
0
    zend_class_entry **trait_aliases;
3634
0
    bool trait_contains_abstract_methods = false;
3635
0
    if (ce->num_traits) {
3636
0
      zend_traits_init_trait_structures(ce, traits_and_interfaces, &trait_exclude_tables, &trait_aliases);
3637
0
      zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods);
3638
0
      zend_do_traits_constant_binding(ce, traits_and_interfaces);
3639
0
      zend_do_traits_property_binding(ce, traits_and_interfaces);
3640
3641
0
      zend_function *fn;
3642
0
      ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3643
0
        zend_fixup_trait_method(fn, ce);
3644
0
      } ZEND_HASH_FOREACH_END();
3645
0
    }
3646
0
    if (parent) {
3647
0
      if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3648
0
        add_dependency_obligation(ce, parent);
3649
0
      }
3650
0
      zend_do_inheritance(ce, parent);
3651
0
    }
3652
0
    if (ce->num_traits) {
3653
0
      if (trait_contains_abstract_methods) {
3654
0
        zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, true, &trait_contains_abstract_methods);
3655
3656
        /* New abstract methods may have been added, make sure to add
3657
         * ZEND_ACC_IMPLICIT_ABSTRACT_CLASS to ce. */
3658
0
        zend_function *fn;
3659
0
        ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3660
0
          zend_fixup_trait_method(fn, ce);
3661
0
        } ZEND_HASH_FOREACH_END();
3662
0
      }
3663
3664
0
      if (trait_exclude_tables) {
3665
0
        for (i = 0; i < ce->num_traits; i++) {
3666
0
          if (traits_and_interfaces[i]) {
3667
0
            if (trait_exclude_tables[i]) {
3668
0
              zend_hash_destroy(trait_exclude_tables[i]);
3669
0
              FREE_HASHTABLE(trait_exclude_tables[i]);
3670
0
            }
3671
0
          }
3672
0
        }
3673
0
        efree(trait_exclude_tables);
3674
0
      }
3675
0
      if (trait_aliases) {
3676
0
        efree(trait_aliases);
3677
0
      }
3678
0
    }
3679
0
    if (ce->num_interfaces) {
3680
      /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3681
0
      uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3682
0
      zend_class_entry **interfaces = emalloc(
3683
0
          sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3684
3685
0
      if (num_parent_interfaces) {
3686
0
        memcpy(interfaces, parent->interfaces,
3687
0
             sizeof(zend_class_entry *) * num_parent_interfaces);
3688
0
      }
3689
0
      memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3690
0
           sizeof(zend_class_entry *) * ce->num_interfaces);
3691
3692
0
      zend_do_implement_interfaces(ce, interfaces);
3693
0
    } else if (parent && parent->num_interfaces) {
3694
0
      zend_do_inherit_interfaces(ce, parent);
3695
0
    }
3696
0
    if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3697
0
      && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3698
0
        ) {
3699
0
      zend_verify_abstract_class(ce);
3700
0
    }
3701
0
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3702
0
      zend_verify_enum(ce);
3703
0
    }
3704
0
    if (ce->num_hooked_prop_variance_checks) {
3705
0
      const zend_property_info *prop_info;
3706
0
      ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
3707
0
        if (prop_info->ce == ce && prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
3708
0
          switch (zend_verify_property_hook_variance(prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
3709
0
            case INHERITANCE_SUCCESS:
3710
0
              break;
3711
0
            case INHERITANCE_ERROR:
3712
0
              zend_hooked_property_variance_error(prop_info);
3713
0
              break;
3714
0
            case INHERITANCE_UNRESOLVED:
3715
0
              add_property_hook_obligation(ce, prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET]);
3716
0
              break;
3717
0
            case INHERITANCE_WARNING:
3718
0
              ZEND_UNREACHABLE();
3719
0
          }
3720
0
        }
3721
0
      } ZEND_HASH_FOREACH_END();
3722
0
    }
3723
3724
    /* Normally Stringable is added during compilation. However, if it is imported from a trait,
3725
     * we need to explicitly add the interface here. */
3726
0
    if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3727
0
      && !zend_class_implements_interface(ce, zend_ce_stringable)) {
3728
0
      ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
3729
0
      ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
3730
0
      ce->num_interfaces++;
3731
0
      ce->interfaces = perealloc(ce->interfaces,
3732
0
                     sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
3733
0
      ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
3734
0
      do_interface_implementation(ce, zend_ce_stringable);
3735
0
    }
3736
3737
0
    zend_build_properties_info_table(ce);
3738
0
  } zend_catch {
3739
    /* Do not leak recorded errors to the next linked class. */
3740
0
    if (!orig_record_errors) {
3741
0
      EG(record_errors) = false;
3742
0
      zend_free_recorded_errors();
3743
0
    }
3744
0
    zend_bailout();
3745
0
  } zend_end_try();
3746
3747
0
  EG(record_errors) = orig_record_errors;
3748
3749
0
  if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3750
0
    zend_inheritance_check_override(ce);
3751
0
    ce->ce_flags |= ZEND_ACC_LINKED;
3752
0
  } else {
3753
0
    ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
3754
0
    if (CG(current_linking_class)) {
3755
0
      ce->ce_flags |= ZEND_ACC_CACHEABLE;
3756
0
    }
3757
0
    load_delayed_classes(ce);
3758
0
    if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3759
0
      resolve_delayed_variance_obligations(ce);
3760
0
    }
3761
0
    if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3762
0
      ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3763
0
    } else {
3764
0
      CG(current_linking_class) = NULL;
3765
0
    }
3766
0
  }
3767
3768
0
  if (!CG(current_linking_class)) {
3769
0
    is_cacheable = 0;
3770
0
  }
3771
0
  CG(current_linking_class) = orig_linking_class;
3772
3773
0
  if (is_cacheable) {
3774
0
    HashTable *ht = (HashTable*)ce->inheritance_cache;
3775
0
    zend_class_entry *new_ce;
3776
3777
0
    ce->inheritance_cache = NULL;
3778
0
    new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3779
0
    if (new_ce) {
3780
0
      zv = zend_hash_find_known_hash(CG(class_table), key);
3781
0
      ce = new_ce;
3782
0
      Z_CE_P(zv) = ce;
3783
0
    }
3784
0
    if (ht) {
3785
0
      zend_hash_destroy(ht);
3786
0
      FREE_HASHTABLE(ht);
3787
0
    }
3788
0
  }
3789
3790
0
  if (!orig_record_errors) {
3791
0
    zend_emit_recorded_errors();
3792
0
    zend_free_recorded_errors();
3793
0
  }
3794
0
  if (traits_and_interfaces) {
3795
0
    free_alloca(traits_and_interfaces, use_heap);
3796
0
  }
3797
3798
0
  if (ZSTR_HAS_CE_CACHE(ce->name)) {
3799
0
    ZSTR_SET_CE_CACHE(ce->name, ce);
3800
0
  }
3801
3802
0
  return ce;
3803
0
}
3804
/* }}} */
3805
3806
/* Check whether early binding is prevented due to unresolved types in inheritance checks. */
3807
static inheritance_status zend_can_early_bind(zend_class_entry *ce, const zend_class_entry *parent_ce) /* {{{ */
3808
5.51k
{
3809
5.51k
  zend_string *key;
3810
5.51k
  zend_function *parent_func;
3811
5.51k
  const zend_property_info *parent_info;
3812
5.51k
  const zend_class_constant *parent_const;
3813
5.51k
  inheritance_status overall_status = INHERITANCE_SUCCESS;
3814
3815
61.6k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3816
61.6k
    zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3817
61.6k
    if (zv) {
3818
1.97k
      zend_function *child_func = Z_FUNC_P(zv);
3819
1.97k
      inheritance_status status =
3820
1.97k
        do_inheritance_check_on_method(
3821
1.97k
          child_func, child_func->common.scope,
3822
1.97k
          parent_func, parent_func->common.scope,
3823
1.97k
          ce, NULL,
3824
1.97k
          ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3825
1.97k
      if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3826
370
        overall_status = INHERITANCE_WARNING;
3827
1.60k
      } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3828
760
        return status;
3829
760
      }
3830
1.97k
    }
3831
61.6k
  } ZEND_HASH_FOREACH_END();
3832
3833
23.6k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3834
23.6k
    const zval *zv;
3835
23.6k
    if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3836
3.53k
      continue;
3837
3.53k
    }
3838
3839
3.52k
    zv = zend_hash_find_known_hash(&ce->properties_info, key);
3840
3.52k
    if (zv) {
3841
1.96k
      const zend_property_info *child_info = Z_PTR_P(zv);
3842
1.96k
      if (ZEND_TYPE_IS_SET(child_info->type)) {
3843
1.93k
        inheritance_status status = verify_property_type_compatibility(parent_info, child_info, prop_get_variance(parent_info), false, false);
3844
1.93k
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3845
983
          return status;
3846
983
        }
3847
1.93k
      }
3848
1.96k
    }
3849
3.52k
  } ZEND_HASH_FOREACH_END();
3850
3851
17.9k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3852
17.9k
    const zval *zv;
3853
17.9k
    if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3854
251
      continue;
3855
251
    }
3856
3857
4.93k
    zv = zend_hash_find_known_hash(&ce->constants_table, key);
3858
4.93k
    if (zv) {
3859
170
      const zend_class_constant *child_const = Z_PTR_P(zv);
3860
170
      if (ZEND_TYPE_IS_SET(child_const->type)) {
3861
156
        inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3862
156
        ZEND_ASSERT(status != INHERITANCE_WARNING);
3863
156
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3864
61
          return status;
3865
61
        }
3866
156
      }
3867
170
    }
3868
4.93k
  } ZEND_HASH_FOREACH_END();
3869
3870
3.71k
  return overall_status;
3871
3.77k
}
3872
/* }}} */
3873
3874
4.68k
static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3875
4.68k
  if (delayed_early_binding) {
3876
0
    if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3877
0
      if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3878
0
        Z_CE_P(delayed_early_binding) = ce;
3879
0
        return true;
3880
0
      }
3881
0
    } else {
3882
      /* If preloading is used, don't replace the existing bucket, add a new one. */
3883
0
      if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3884
0
        return true;
3885
0
      }
3886
0
    }
3887
0
    zend_class_entry *old_ce = zend_hash_find_ptr(EG(class_table), lcname);
3888
0
    ZEND_ASSERT(old_ce);
3889
0
    zend_class_redeclaration_error(E_COMPILE_ERROR, old_ce);
3890
0
    return false;
3891
0
  }
3892
4.68k
  if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3893
2.43k
    return true;
3894
2.43k
  }
3895
2.25k
  return false;
3896
4.68k
}
3897
3898
ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding) /* {{{ */
3899
5.51k
{
3900
5.51k
  inheritance_status status;
3901
5.51k
  zend_class_entry *proto = NULL;
3902
5.51k
  zend_class_entry *orig_linking_class;
3903
3904
5.51k
  if (ce->ce_flags & ZEND_ACC_LINKED) {
3905
0
    ZEND_ASSERT(ce->parent == NULL);
3906
0
    if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3907
0
      return NULL;
3908
0
    }
3909
0
    zend_observer_class_linked_notify(ce, lcname);
3910
0
    return ce;
3911
0
  }
3912
3913
5.51k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3914
5.51k
  UPDATE_IS_CACHEABLE(parent_ce);
3915
5.51k
  if (is_cacheable) {
3916
0
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3917
0
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3918
0
      if (ret) {
3919
0
        if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
3920
0
          return NULL;
3921
0
        }
3922
0
        zend_observer_class_linked_notify(ret, lcname);
3923
0
        return ret;
3924
0
      }
3925
0
    } else {
3926
0
      is_cacheable = 0;
3927
0
    }
3928
0
    proto = ce;
3929
0
  }
3930
3931
5.51k
  orig_linking_class = CG(current_linking_class);
3932
5.51k
  CG(current_linking_class) = NULL;
3933
5.51k
  status = zend_can_early_bind(ce, parent_ce);
3934
5.51k
  CG(current_linking_class) = orig_linking_class;
3935
5.51k
  if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3936
4.68k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3937
      /* Lazy class loading */
3938
0
      ce = zend_lazy_class_load(ce);
3939
4.68k
    } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3940
      /* Lazy class loading */
3941
0
      ce = zend_lazy_class_load(ce);
3942
0
      ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3943
0
    }
3944
3945
4.68k
    if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3946
2.25k
      return NULL;
3947
2.25k
    }
3948
3949
2.43k
    orig_linking_class = CG(current_linking_class);
3950
2.43k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3951
3952
2.43k
    bool orig_record_errors = EG(record_errors);
3953
3954
2.43k
    zend_try{
3955
2.43k
      CG(zend_lineno) = ce->info.user.line_start;
3956
3957
2.43k
      if (!orig_record_errors) {
3958
0
        zend_begin_record_errors();
3959
0
      }
3960
3961
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3962
      zend_link_hooked_object_iter(ce);
3963
#endif
3964
3965
2.43k
      zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3966
2.43k
      if (parent_ce && parent_ce->num_interfaces) {
3967
460
        zend_do_inherit_interfaces(ce, parent_ce);
3968
460
      }
3969
2.43k
      zend_build_properties_info_table(ce);
3970
2.43k
      if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
3971
17
        zend_verify_abstract_class(ce);
3972
17
      }
3973
2.43k
      zend_inheritance_check_override(ce);
3974
2.43k
      ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3975
2.43k
      ce->ce_flags |= ZEND_ACC_LINKED;
3976
3977
2.04k
      CG(current_linking_class) = orig_linking_class;
3978
2.04k
    } zend_catch {
3979
0
      if (!orig_record_errors) {
3980
0
        EG(record_errors) = false;
3981
0
        zend_free_recorded_errors();
3982
0
      }
3983
0
      zend_bailout();
3984
2.04k
    } zend_end_try();
3985
3986
2.04k
    if (is_cacheable) {
3987
0
      HashTable *ht = (HashTable*)ce->inheritance_cache;
3988
0
      zend_class_entry *new_ce;
3989
3990
0
      ce->inheritance_cache = NULL;
3991
0
      new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3992
0
      if (new_ce) {
3993
0
        zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3994
0
        ce = new_ce;
3995
0
        Z_CE_P(zv) = ce;
3996
0
      }
3997
0
      if (ht) {
3998
0
        zend_hash_destroy(ht);
3999
0
        FREE_HASHTABLE(ht);
4000
0
      }
4001
0
    }
4002
4003
2.04k
    if (!orig_record_errors) {
4004
0
      zend_emit_recorded_errors();
4005
0
      zend_free_recorded_errors();
4006
0
    }
4007
4008
2.04k
    if (ZSTR_HAS_CE_CACHE(ce->name)) {
4009
0
      ZSTR_SET_CE_CACHE(ce->name, ce);
4010
0
    }
4011
2.04k
    zend_observer_class_linked_notify(ce, lcname);
4012
4013
2.04k
    return ce;
4014
2.04k
  }
4015
827
  return NULL;
4016
5.51k
}
4017
/* }}} */