Coverage Report

Created: 2025-07-23 06:33

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