Coverage Report

Created: 2026-02-09 07:07

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