Coverage Report

Created: 2025-11-16 06:23

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