Coverage Report

Created: 2025-12-14 06:10

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