Coverage Report

Created: 2026-10-28 06:20

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