Coverage Report

Created: 2026-06-13 07:01

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