Coverage Report

Created: 2025-12-14 06:09

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