Coverage Report

Created: 2026-04-01 06:49

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