Coverage Report

Created: 2026-06-02 06:39

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