Coverage Report

Created: 2026-09-14 06:25

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
77
) {
73
77
  const zend_type_list *const old_list = ZEND_TYPE_LIST(*parent_type);
74
77
  size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
75
77
  zend_type_list *new_list = use_arena
76
77
    ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
77
78
77
  memcpy(new_list, old_list, size);
79
77
  ZEND_TYPE_SET_LIST(*parent_type, new_list);
80
77
  if (use_arena) {
81
77
    ZEND_TYPE_FULL_MASK(*parent_type) |= _ZEND_TYPE_ARENA_BIT;
82
77
  }
83
84
77
  zend_type *list_type;
85
240
  ZEND_TYPE_LIST_FOREACH_MUTABLE(new_list, list_type) {
86
240
    zend_type_copy_ctor(list_type, use_arena, persistent);
87
240
  } ZEND_TYPE_LIST_FOREACH_END();
88
77
}
89
90
3.37k
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
91
3.37k
  if (ZEND_TYPE_HAS_LIST(*type)) {
92
77
    zend_type_list_copy_ctor(type, use_arena, persistent);
93
3.29k
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
94
289
    zend_string_addref(ZEND_TYPE_NAME(*type));
95
289
  }
96
3.37k
}
97
98
static zend_function *zend_duplicate_internal_function(const zend_function *func, const zend_class_entry *ce) /* {{{ */
99
35.8k
{
100
35.8k
  zend_function *new_function;
101
102
35.8k
  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
14.9k
    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
107
14.9k
    memcpy(new_function, func, sizeof(zend_internal_function));
108
14.9k
    new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
109
14.9k
  }
110
35.8k
  if (EXPECTED(new_function->common.function_name)) {
111
35.8k
    zend_string_addref(new_function->common.function_name);
112
35.8k
  }
113
35.8k
  return new_function;
114
35.8k
}
115
/* }}} */
116
117
static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
118
39.6k
{
119
39.6k
  if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
120
35.8k
    return zend_duplicate_internal_function(func, ce);
121
35.8k
  } else {
122
3.77k
    if (func->op_array.refcount) {
123
3.08k
      (*func->op_array.refcount)++;
124
3.08k
    }
125
3.77k
    if (EXPECTED(func->op_array.function_name)) {
126
3.77k
      zend_string_addref(func->op_array.function_name);
127
3.77k
    }
128
3.77k
    return func;
129
3.77k
  }
130
39.6k
}
131
/* }}} */
132
133
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
134
8.04k
{
135
8.04k
  zend_class_entry *parent = ce->parent;
136
137
8.04k
  ZEND_ASSERT(parent != NULL);
138
139
  /* You cannot change create_object */
140
8.04k
  ce->create_object = parent->create_object;
141
142
  /* Inherit special functions if needed */
143
8.04k
  if (EXPECTED(!ce->get_iterator)) {
144
7.39k
    ce->get_iterator = parent->get_iterator;
145
7.39k
  }
146
8.04k
  if (EXPECTED(!ce->__get)) {
147
7.86k
    ce->__get = parent->__get;
148
7.86k
  }
149
8.04k
  if (EXPECTED(!ce->__set)) {
150
8.00k
    ce->__set = parent->__set;
151
8.00k
  }
152
8.04k
  if (EXPECTED(!ce->__unset)) {
153
7.99k
    ce->__unset = parent->__unset;
154
7.99k
  }
155
8.04k
  if (EXPECTED(!ce->__isset)) {
156
7.98k
    ce->__isset = parent->__isset;
157
7.98k
  }
158
8.04k
  if (EXPECTED(!ce->__call)) {
159
7.97k
    ce->__call = parent->__call;
160
7.97k
  }
161
8.04k
  if (EXPECTED(!ce->__callstatic)) {
162
7.98k
    ce->__callstatic = parent->__callstatic;
163
7.98k
  }
164
8.04k
  if (EXPECTED(!ce->__tostring)) {
165
7.93k
    ce->__tostring = parent->__tostring;
166
7.93k
  }
167
8.04k
  if (EXPECTED(!ce->clone)) {
168
8.02k
    ce->clone = parent->clone;
169
8.02k
  }
170
8.04k
  if (EXPECTED(!ce->__serialize)) {
171
8.04k
    ce->__serialize = parent->__serialize;
172
8.04k
  }
173
8.04k
  if (EXPECTED(!ce->__unserialize)) {
174
8.02k
    ce->__unserialize = parent->__unserialize;
175
8.02k
  }
176
8.04k
  if (EXPECTED(!ce->serialize)) {
177
8.04k
    ce->serialize = parent->serialize;
178
8.04k
  }
179
8.04k
  if (EXPECTED(!ce->unserialize)) {
180
8.04k
    ce->unserialize = parent->unserialize;
181
8.04k
  }
182
8.04k
  if (!ce->destructor) {
183
7.99k
    ce->destructor = parent->destructor;
184
7.99k
  }
185
8.04k
  if (EXPECTED(!ce->__debugInfo)) {
186
8.01k
    ce->__debugInfo = parent->__debugInfo;
187
8.01k
  }
188
189
8.04k
  if (ce->constructor) {
190
1.00k
    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
1.00k
    return;
196
1.00k
  }
197
198
7.04k
  ce->constructor = parent->constructor;
199
7.04k
}
200
/* }}} */
201
202
const char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
203
439
{
204
439
  if (fn_flags & ZEND_ACC_PUBLIC) {
205
152
    return "public";
206
287
  } else if (fn_flags & ZEND_ACC_PRIVATE) {
207
203
    return "private";
208
203
  } else {
209
84
    ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
210
84
    return "protected";
211
84
  }
212
439
}
213
/* }}} */
214
215
static const char *zend_asymmetric_visibility_string(uint32_t fn_flags) /* {{{ */
216
34
{
217
34
  if (fn_flags & ZEND_ACC_PRIVATE_SET) {
218
0
    return "private(set)";
219
34
  } else if (fn_flags & ZEND_ACC_PROTECTED_SET) {
220
5
    return "protected(set)";
221
29
  } else {
222
29
    ZEND_ASSERT(!(fn_flags & ZEND_ACC_PUBLIC_SET));
223
29
    return "omitted";
224
29
  }
225
34
}
226
227
173k
static zend_string *resolve_class_name(const zend_class_entry *scope, zend_string *name) {
228
173k
  ZEND_ASSERT(scope);
229
173k
  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
173k
  } else if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_SELF))) {
236
83
    return scope->name;
237
173k
  } else {
238
173k
    return name;
239
173k
  }
240
173k
}
241
242
10.3k
static bool class_visible(const zend_class_entry *ce) {
243
10.3k
  if (ce->type == ZEND_INTERNAL_CLASS) {
244
827
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
245
9.50k
  } else {
246
9.50k
    ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
247
9.50k
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
248
1.31k
      || ce->info.user.filename == CG(compiled_filename);
249
9.50k
  }
250
10.3k
}
251
252
1.07k
static zend_always_inline void register_unresolved_class(zend_string *name) {
253
  /* We'll autoload this class and process delayed variance obligations later. */
254
1.07k
  if (!CG(delayed_autoloads)) {
255
313
    ALLOC_HASHTABLE(CG(delayed_autoloads));
256
313
    zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
257
313
  }
258
1.07k
  zend_hash_add_empty_element(CG(delayed_autoloads), name);
259
1.07k
}
260
261
static zend_class_entry *lookup_class_ex(
262
224k
    zend_class_entry *scope, zend_string *name, bool register_unresolved) {
263
224k
  zend_class_entry *ce;
264
224k
  bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
265
266
224k
  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
223k
  ce = zend_lookup_class_ex(
279
223k
      name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
280
281
223k
  if (!CG(in_compilation) || in_preload) {
282
6.62k
    if (ce) {
283
3.71k
      return ce;
284
3.71k
    }
285
286
2.91k
    if (register_unresolved) {
287
1.07k
      register_unresolved_class(name);
288
1.07k
    }
289
217k
  } else {
290
217k
    if (ce && class_visible(ce)) {
291
10.3k
      return ce;
292
10.3k
    }
293
294
    /* The current class may not be registered yet, so check for it explicitly. */
295
206k
    if (zend_string_equals_ci(scope->name, name)) {
296
947
      return scope;
297
947
    }
298
206k
  }
299
300
208k
  return NULL;
301
223k
}
302
303
208k
static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name) {
304
208k
  return lookup_class_ex(scope, name, /* register_unresolved */ false);
305
208k
}
306
307
/* Instanceof that's safe to use on unlinked classes. */
308
3.77k
static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) {
309
3.77k
  if (ce1 == ce2) {
310
310
    return true;
311
310
  }
312
313
3.46k
  if (ce1->ce_flags & ZEND_ACC_LINKED) {
314
3.14k
    return instanceof_function(ce1, ce2);
315
3.14k
  }
316
317
317
  if (ce1->parent) {
318
303
    const zend_class_entry *parent_ce;
319
303
    if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
320
157
      parent_ce = ce1->parent;
321
157
    } else {
322
146
      parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
323
146
        ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
324
146
    }
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
303
    if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
329
205
      return true;
330
205
    }
331
303
  }
332
333
112
  if (ce1->num_interfaces) {
334
40
    uint32_t i;
335
40
    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
14
      for (i = 0; i < ce1->num_interfaces; i++) {
339
14
        if (unlinked_instanceof(ce1->interfaces[i], ce2)) {
340
14
          return true;
341
14
        }
342
14
      }
343
26
    } else {
344
42
      for (i = 0; i < ce1->num_interfaces; i++) {
345
34
        const zend_class_entry *ce = zend_lookup_class_ex(
346
34
          ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
347
34
          ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
348
        /* Avoid recursing if class implements itself. */
349
34
        if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
350
18
          return true;
351
18
        }
352
34
      }
353
26
    }
354
40
  }
355
356
80
  return false;
357
112
}
358
359
static bool zend_type_permits_self(
360
201
    const zend_type type, const zend_class_entry *scope, zend_class_entry *self) {
361
201
  if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
362
27
    return true;
363
27
  }
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
174
  const zend_type *single_type;
369
420
  ZEND_TYPE_FOREACH(type, single_type) {
370
420
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
371
233
      zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
372
233
      const zend_class_entry *ce = lookup_class(self, name);
373
233
      if (ce && unlinked_instanceof(self, ce)) {
374
116
        return true;
375
116
      }
376
233
    }
377
420
  } ZEND_TYPE_FOREACH_END();
378
58
  return false;
379
174
}
380
381
static void track_class_dependency(zend_class_entry *ce, zend_string *class_name)
382
2.65k
{
383
2.65k
  HashTable *ht;
384
385
2.65k
  ZEND_ASSERT(class_name);
386
2.65k
  if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
387
1.58k
    return;
388
1.58k
  } else if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_SELF))
389
1.06k
          || zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_PARENT))) {
390
0
    return;
391
0
  }
392
393
1.06k
#ifndef ZEND_WIN32
394
  /* On non-Windows systems, internal classes are always the same,
395
   * so there is no need to explicitly track them. */
396
1.06k
  if (ce->type == ZEND_INTERNAL_CLASS) {
397
149
    return;
398
149
  }
399
916
#endif
400
401
916
  ht = (HashTable*)CG(current_linking_class)->inheritance_cache;
402
403
916
  if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
404
    // TODO: dependency on not-immutable class ???
405
40
    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
40
    CG(current_linking_class)->ce_flags &= ~ZEND_ACC_CACHEABLE;
411
40
    CG(current_linking_class) = NULL;
412
40
    return;
413
40
  }
414
415
  /* Record dependency */
416
876
  if (!ht) {
417
179
    ALLOC_HASHTABLE(ht);
418
179
    zend_hash_init(ht, 0, NULL, NULL, 0);
419
179
    CG(current_linking_class)->inheritance_cache = (zend_inheritance_cache_entry*)ht;
420
179
  }
421
876
  zend_hash_add_ptr(ht, class_name, ce);
422
876
}
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
33.0k
{
429
33.0k
  ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(fe_type));
430
33.0k
  bool have_unresolved = false;
431
33.0k
  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
131k
  ZEND_TYPE_FOREACH(fe_type, single_type) {
436
131k
    zend_class_entry *fe_ce;
437
131k
    zend_string *fe_class_name = NULL;
438
131k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
439
98.8k
      fe_class_name =
440
98.8k
        resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
441
98.8k
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
442
9.81k
        return INHERITANCE_SUCCESS;
443
9.81k
      }
444
445
89.0k
      if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
446
89.0k
      fe_ce = lookup_class(fe_scope, fe_class_name);
447
89.0k
    } 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
89.0k
    if (!fe_ce || !proto_ce) {
455
87.9k
      have_unresolved = true;
456
87.9k
      continue;
457
87.9k
    }
458
1.09k
    if (unlinked_instanceof(fe_ce, proto_ce)) {
459
52
      track_class_dependency(fe_ce, fe_class_name);
460
52
      track_class_dependency(proto_ce, proto_class_name);
461
52
      return INHERITANCE_SUCCESS;
462
52
    }
463
1.09k
  } ZEND_TYPE_FOREACH_END();
464
465
23.1k
  return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
466
33.0k
}
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
11.3k
    zend_class_entry *proto_scope, const zend_type proto_type) {
472
11.3k
  zend_class_entry *fe_ce = NULL;
473
11.3k
  bool have_unresolved = false;
474
475
  /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
476
11.3k
  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
617
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
481
617
    if (!fe_ce) {
482
392
      have_unresolved = true;
483
392
    } else {
484
225
      track_class_dependency(fe_ce, fe_class_name);
485
225
      return INHERITANCE_SUCCESS;
486
225
    }
487
617
  }
488
489
  /* If the parent has 'callable' as a return type, then Closure satisfies the co-variant check */
490
11.1k
  if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_CALLABLE) {
491
240
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
492
240
    if (!fe_ce) {
493
131
      have_unresolved = true;
494
131
    } else if (fe_ce == zend_ce_closure) {
495
87
      track_class_dependency(fe_ce, fe_class_name);
496
87
      return INHERITANCE_SUCCESS;
497
87
    }
498
240
  }
499
500
  /* If the parent has 'static' as a return type, then final classes could replace it with self */
501
11.0k
  if ((ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_STATIC) && (fe_scope->ce_flags & ZEND_ACC_FINAL)) {
502
128
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
503
128
    if (!fe_ce) {
504
12
      have_unresolved = true;
505
116
    } else if (fe_ce == fe_scope) {
506
80
      track_class_dependency(fe_ce, fe_class_name);
507
80
      return INHERITANCE_SUCCESS;
508
80
    }
509
128
  }
510
511
11.0k
  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
11.0k
  bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
516
34.4k
  ZEND_TYPE_FOREACH(proto_type, single_type) {
517
34.4k
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
518
3.83k
      inheritance_status subtype_status = zend_is_class_subtype_of_type(
519
3.83k
        fe_scope, fe_class_name, proto_scope, *single_type);
520
521
3.83k
      switch (subtype_status) {
522
543
        case INHERITANCE_ERROR:
523
543
          if (is_intersection) {
524
0
            return INHERITANCE_ERROR;
525
0
          }
526
543
          continue;
527
3.08k
        case INHERITANCE_UNRESOLVED:
528
3.08k
          have_unresolved = true;
529
3.08k
          continue;
530
207
        case INHERITANCE_SUCCESS:
531
207
          if (!is_intersection) {
532
207
            return INHERITANCE_SUCCESS;
533
207
          }
534
0
          continue;
535
0
        default: ZEND_UNREACHABLE();
536
3.83k
      }
537
3.83k
    }
538
539
19.5k
    zend_class_entry *proto_ce;
540
19.5k
    zend_string *proto_class_name = NULL;
541
19.5k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
542
18.7k
      proto_class_name =
543
18.7k
        resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
544
18.7k
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
545
2.76k
        if (!is_intersection) {
546
2.54k
          return INHERITANCE_SUCCESS;
547
2.54k
        }
548
220
        continue;
549
2.76k
      }
550
551
15.9k
      if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
552
15.9k
      proto_ce = lookup_class(proto_scope, proto_class_name);
553
15.9k
    } else {
554
      /* standard type */
555
869
      ZEND_ASSERT(!is_intersection);
556
869
      continue;
557
869
    }
558
559
15.9k
    if (!fe_ce || !proto_ce) {
560
13.7k
      have_unresolved = true;
561
13.7k
      continue;
562
13.7k
    }
563
2.22k
    if (unlinked_instanceof(fe_ce, proto_ce)) {
564
1.04k
      track_class_dependency(fe_ce, fe_class_name);
565
1.04k
      track_class_dependency(proto_ce, proto_class_name);
566
1.04k
      if (!is_intersection) {
567
606
        return INHERITANCE_SUCCESS;
568
606
      }
569
1.18k
    } else {
570
1.18k
      if (is_intersection) {
571
559
        return INHERITANCE_ERROR;
572
559
      }
573
1.18k
    }
574
2.22k
  } ZEND_TYPE_FOREACH_END();
575
576
7.08k
  if (have_unresolved) {
577
6.21k
    return INHERITANCE_UNRESOLVED;
578
6.21k
  }
579
874
  return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
580
7.08k
}
581
582
53.8k
static zend_string *get_class_from_type(const zend_class_entry *scope, const zend_type single_type) {
583
53.8k
  if (ZEND_TYPE_HAS_NAME(single_type)) {
584
40.8k
    return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
585
40.8k
  }
586
13.0k
  return NULL;
587
53.8k
}
588
589
8.23k
static void register_unresolved_classes(zend_class_entry *scope, const zend_type type) {
590
8.23k
  const zend_type *single_type;
591
26.7k
  ZEND_TYPE_FOREACH(type, single_type) {
592
26.7k
    if (ZEND_TYPE_HAS_LIST(*single_type)) {
593
2.82k
      register_unresolved_classes(scope, *single_type);
594
2.82k
      continue;
595
2.82k
    }
596
15.6k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
597
15.3k
      zend_string *class_name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
598
15.3k
      lookup_class_ex(scope, class_name, /* register_unresolved */ true);
599
15.3k
    }
600
15.6k
  } ZEND_TYPE_FOREACH_END();
601
8.23k
}
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
11.5k
{
607
11.5k
  bool have_unresolved = false;
608
11.5k
  const zend_type *single_type;
609
11.5k
  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
11.5k
  if (proto_type_mask & MAY_BE_OBJECT) {
616
365
    ZEND_TYPE_FOREACH(fe_type, single_type) {
617
365
      zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
618
365
      if (!fe_class_name) {
619
0
        continue;
620
0
      }
621
243
      zend_class_entry *fe_ce = lookup_class(fe_scope, fe_class_name);
622
243
      if (fe_ce) {
623
75
        track_class_dependency(fe_ce, fe_class_name);
624
75
        return INHERITANCE_SUCCESS;
625
168
      } else {
626
168
        have_unresolved = true;
627
168
      }
628
243
    } ZEND_TYPE_FOREACH_END();
629
122
  }
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
11.5k
  inheritance_status early_exit_status =
636
11.5k
    ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
637
53.3k
  ZEND_TYPE_FOREACH(proto_type, single_type) {
638
53.3k
    inheritance_status status;
639
640
53.3k
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
641
8.64k
      status = zend_is_intersection_subtype_of_type(
642
8.64k
        fe_scope, fe_type, proto_scope, *single_type);
643
33.1k
    } else {
644
33.1k
      zend_string *proto_class_name = get_class_from_type(proto_scope, *single_type);
645
33.1k
      if (!proto_class_name) {
646
162
        continue;
647
162
      }
648
649
33.0k
      zend_class_entry *proto_ce = NULL;
650
33.0k
      status = zend_is_intersection_subtype_of_class(
651
33.0k
        fe_scope, fe_type, proto_scope, proto_class_name, proto_ce);
652
33.0k
    }
653
654
41.6k
    if (status == early_exit_status) {
655
985
      return status;
656
985
    }
657
40.6k
    if (status == INHERITANCE_UNRESOLVED) {
658
31.0k
      have_unresolved = true;
659
31.0k
    }
660
40.6k
  } ZEND_TYPE_FOREACH_END();
661
662
10.5k
  if (have_unresolved) {
663
9.63k
    return INHERITANCE_UNRESOLVED;
664
9.63k
  }
665
666
898
  return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
667
10.5k
}
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
22.6k
{
673
22.6k
  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
22.6k
  if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
678
1.91k
      !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
679
1.90k
    return INHERITANCE_SUCCESS;
680
1.90k
  }
681
682
  /* Builtin types may be removed, but not added */
683
20.7k
  uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
684
20.7k
  uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
685
20.7k
  uint32_t added_types = fe_type_mask & ~proto_type_mask;
686
20.7k
  if (added_types) {
687
1.19k
    if ((added_types & MAY_BE_STATIC)
688
201
        && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
689
      /* Replacing type that accepts self with static is okay */
690
143
      added_types &= ~MAY_BE_STATIC;
691
143
    }
692
693
1.19k
    if (added_types == MAY_BE_NEVER) {
694
      /* never is the bottom type */
695
24
      return INHERITANCE_SUCCESS;
696
24
    }
697
698
1.17k
    if (added_types) {
699
      /* Otherwise adding new types is illegal */
700
1.02k
      return INHERITANCE_ERROR;
701
1.02k
    }
702
1.17k
  }
703
704
19.7k
  inheritance_status early_exit_status;
705
19.7k
  bool have_unresolved = false;
706
707
19.7k
  if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
708
724
    early_exit_status =
709
724
      ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
710
724
    inheritance_status status = zend_is_intersection_subtype_of_type(
711
724
      fe_scope, fe_type, proto_scope, proto_type);
712
713
724
    if (status == early_exit_status) {
714
166
      return status;
715
166
    }
716
558
    if (status == INHERITANCE_UNRESOLVED) {
717
257
      have_unresolved = true;
718
257
    }
719
19.0k
  } 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
19.0k
    early_exit_status = INHERITANCE_ERROR;
725
19.0k
    const zend_type *single_type;
726
41.6k
    ZEND_TYPE_FOREACH(fe_type, single_type) {
727
41.6k
      inheritance_status status;
728
      /* Union has an intersection type as it's member */
729
41.6k
      if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
730
2.22k
        status = zend_is_intersection_subtype_of_type(
731
2.22k
          fe_scope, *single_type, proto_scope, proto_type);
732
20.4k
      } else {
733
20.4k
        zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
734
20.4k
        if (!fe_class_name) {
735
12.8k
          continue;
736
12.8k
        }
737
738
7.56k
        status = zend_is_class_subtype_of_type(
739
7.56k
          fe_scope, fe_class_name, proto_scope, proto_type);
740
7.56k
      }
741
742
9.78k
      if (status == early_exit_status) {
743
634
        return status;
744
634
      }
745
9.15k
      if (status == INHERITANCE_UNRESOLVED) {
746
4.46k
        have_unresolved = true;
747
4.46k
      }
748
9.15k
    } ZEND_TYPE_FOREACH_END();
749
19.0k
  }
750
751
18.9k
  if (!have_unresolved) {
752
16.2k
    return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
753
16.2k
  }
754
755
2.70k
  register_unresolved_classes(fe_scope, fe_type);
756
2.70k
  register_unresolved_classes(proto_scope, proto_type);
757
2.70k
  return INHERITANCE_UNRESOLVED;
758
18.9k
}
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
7.59k
{
764
7.59k
  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
3.42k
    return INHERITANCE_SUCCESS;
767
3.42k
  }
768
769
4.17k
  if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
770
    /* Child defines a type, but parent doesn't, violates LSP */
771
27
    return INHERITANCE_ERROR;
772
27
  }
773
774
  /* Contravariant type check is performed as a covariant type check with swapped
775
   * argument order. */
776
4.14k
  return zend_perform_covariant_type_check(
777
4.14k
    proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
778
4.17k
}
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
16.7k
{
788
16.7k
  uint32_t num_args, proto_num_args, fe_num_args;
789
16.7k
  inheritance_status status, local_status;
790
16.7k
  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
16.7k
  ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
796
16.7k
    && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
797
16.7k
      && (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
16.7k
  ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
802
16.7k
      || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
803
804
  /* The number of required arguments cannot increase. */
805
16.7k
  if (proto->common.required_num_args < fe->common.required_num_args) {
806
123
    return INHERITANCE_ERROR;
807
123
  }
808
809
  /* by-ref constraints on return values are covariant */
810
16.6k
  if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
811
189
    && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
812
66
    return INHERITANCE_ERROR;
813
66
  }
814
815
16.5k
  proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
816
16.5k
  fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
817
818
  /* A variadic function cannot become non-variadic */
819
16.5k
  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
16.5k
  proto_num_args = proto->common.num_args + proto_is_variadic;
825
16.5k
  fe_num_args = fe->common.num_args + fe_is_variadic;
826
16.5k
  num_args = MAX(proto_num_args, fe_num_args);
827
828
16.5k
  status = INHERITANCE_SUCCESS;
829
24.3k
  for (uint32_t i = 0; i < num_args; i++) {
830
8.34k
    zend_arg_info *proto_arg_info =
831
8.34k
      i < proto_num_args ? &proto->common.arg_info[i] :
832
8.34k
      proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
833
8.34k
    zend_arg_info *fe_arg_info =
834
8.34k
      i < fe_num_args ? &fe->common.arg_info[i] :
835
8.34k
      fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
836
8.34k
    if (!proto_arg_info) {
837
      /* A new (optional) argument has been added, which is fine. */
838
522
      continue;
839
522
    }
840
7.82k
    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
227
      return INHERITANCE_ERROR;
845
227
    }
846
847
7.59k
    local_status = zend_do_perform_arg_type_hint_check(
848
7.59k
      fe_scope, fe_arg_info, proto_scope, proto_arg_info);
849
850
7.59k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
851
915
      if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
852
338
        return INHERITANCE_ERROR;
853
338
      }
854
577
      ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
855
577
      status = INHERITANCE_UNRESOLVED;
856
577
    }
857
858
    /* by-ref constraints on arguments are invariant */
859
7.25k
    if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
860
34
      return INHERITANCE_ERROR;
861
34
    }
862
7.25k
  }
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
15.9k
  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
14.0k
    if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
869
384
      if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
870
150
        return INHERITANCE_ERROR;
871
150
      }
872
234
      if (status == INHERITANCE_SUCCESS) {
873
234
        return INHERITANCE_WARNING;
874
234
      }
875
0
      return status;
876
234
    }
877
878
13.6k
    local_status = zend_perform_covariant_type_check(
879
13.6k
      fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
880
881
13.6k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
882
1.48k
      if (local_status == INHERITANCE_ERROR
883
799
          && ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
884
375
        local_status = INHERITANCE_WARNING;
885
375
      }
886
1.48k
      return local_status;
887
1.48k
    }
888
13.6k
  }
889
890
14.1k
  return status;
891
15.9k
}
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.31k
{
897
4.31k
  if (ZEND_TYPE_IS_SET(arg_info->type)) {
898
3.49k
    zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
899
3.49k
    smart_str_append(str, type_str);
900
3.49k
    zend_string_release(type_str);
901
3.49k
    if (!return_hint) {
902
1.94k
      smart_str_appendc(str, ' ');
903
1.94k
    }
904
3.49k
  }
905
4.31k
}
906
/* }}} */
907
908
static ZEND_COLD zend_string *zend_get_function_declaration(
909
    const zend_function *fptr, const zend_class_entry *scope) /* {{{ */
910
2.40k
{
911
2.40k
  smart_str str = {0};
912
913
2.40k
  if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
914
298
    smart_str_appendc(&str, '&');
915
298
  }
916
917
2.40k
  if (fptr->common.scope) {
918
2.40k
    if (fptr->common.scope->ce_flags & ZEND_ACC_ANON_CLASS) {
919
      /* cut off on NULL byte ... class@anonymous */
920
7
      smart_str_appends(&str, ZSTR_VAL(fptr->common.scope->name));
921
2.39k
    } else {
922
2.39k
      smart_str_append(&str, fptr->common.scope->name);
923
2.39k
    }
924
2.40k
    smart_str_appends(&str, "::");
925
2.40k
  }
926
927
2.40k
  smart_str_append(&str, fptr->common.function_name);
928
2.40k
  smart_str_appendc(&str, '(');
929
930
2.40k
  if (fptr->common.arg_info) {
931
2.21k
    uint32_t num_args, required;
932
2.21k
    zend_arg_info *arg_info = fptr->common.arg_info;
933
934
2.21k
    required = fptr->common.required_num_args;
935
2.21k
    num_args = fptr->common.num_args;
936
2.21k
    if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
937
49
      num_args++;
938
49
    }
939
4.98k
    for (uint32_t i = 0; i < num_args;) {
940
2.77k
      zend_append_type_hint(&str, scope, arg_info, false);
941
942
2.77k
      if (ZEND_ARG_SEND_MODE(arg_info)) {
943
98
        smart_str_appendc(&str, '&');
944
98
      }
945
946
2.77k
      if (ZEND_ARG_IS_VARIADIC(arg_info)) {
947
49
        smart_str_appends(&str, "...");
948
49
      }
949
950
2.77k
      smart_str_appendc(&str, '$');
951
2.77k
      smart_str_append(&str, arg_info->name);
952
953
2.77k
      if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
954
1.45k
        smart_str_appends(&str, " = ");
955
956
1.45k
        if (fptr->type == ZEND_INTERNAL_FUNCTION) {
957
457
          if (arg_info->default_value) {
958
457
            smart_str_append(&str, arg_info->default_value);
959
457
          } else {
960
0
            smart_str_appends(&str, "<default>");
961
0
          }
962
999
        } else {
963
999
          zend_op *precv = NULL;
964
999
          {
965
999
            uint32_t idx  = i;
966
999
            zend_op *op = fptr->op_array.opcodes;
967
999
            const zend_op *end = op + fptr->op_array.last;
968
969
999
            ++idx;
970
6.42k
            while (op < end) {
971
5.42k
              if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
972
3.70k
                  && op->op1.num == (zend_ulong)idx)
973
999
              {
974
999
                precv = op;
975
999
              }
976
5.42k
              ++op;
977
5.42k
            }
978
999
          }
979
999
          if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
980
999
            zval *zv = RT_CONSTANT(precv, precv->op2);
981
982
999
            if (Z_TYPE_P(zv) == IS_FALSE) {
983
14
              smart_str_appends(&str, "false");
984
985
            } else if (Z_TYPE_P(zv) == IS_TRUE) {
985
6
              smart_str_appends(&str, "true");
986
979
            } else if (Z_TYPE_P(zv) == IS_NULL) {
987
93
              smart_str_appends(&str, "null");
988
886
            } else if (Z_TYPE_P(zv) == IS_STRING) {
989
57
              smart_str_appendc(&str, '\'');
990
57
              smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
991
57
              if (Z_STRLEN_P(zv) > 10) {
992
19
                smart_str_appends(&str, "...");
993
19
              }
994
57
              smart_str_appendc(&str, '\'');
995
829
            } else if (Z_TYPE_P(zv) == IS_ARRAY) {
996
19
              if (zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0) {
997
12
                smart_str_appends(&str, "[]");
998
12
              } else {
999
7
                smart_str_appends(&str, "[...]");
1000
7
              }
1001
810
            } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
1002
756
              zend_ast *ast = Z_ASTVAL_P(zv);
1003
756
              if (ast->kind == ZEND_AST_CONSTANT) {
1004
370
                smart_str_append(&str, zend_ast_get_constant_name(ast));
1005
386
              } else if (ast->kind == ZEND_AST_CLASS_CONST
1006
57
               && ast->child[1]->kind == ZEND_AST_ZVAL
1007
51
               && Z_TYPE_P(zend_ast_get_zval(ast->child[1])) == IS_STRING) {
1008
51
                smart_str_append(&str, zend_ast_get_str(ast->child[0]));
1009
51
                smart_str_appends(&str, "::");
1010
51
                smart_str_append(&str, zend_ast_get_str(ast->child[1]));
1011
335
              } else {
1012
335
                smart_str_appends(&str, "<expression>");
1013
335
              }
1014
756
            } else {
1015
54
              zend_string *tmp_zv_str;
1016
54
              zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str);
1017
54
              smart_str_append(&str, zv_str);
1018
54
              zend_tmp_string_release(tmp_zv_str);
1019
54
            }
1020
999
          }
1021
999
        }
1022
1.45k
      }
1023
1024
2.77k
      if (++i < num_args) {
1025
1.29k
        smart_str_appends(&str, ", ");
1026
1.29k
      }
1027
2.77k
      arg_info++;
1028
2.77k
    }
1029
2.21k
  }
1030
1031
2.40k
  smart_str_appendc(&str, ')');
1032
1033
2.40k
  if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1034
1.54k
    smart_str_appends(&str, ": ");
1035
1.54k
    zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, true);
1036
1.54k
  }
1037
2.40k
  smart_str_0(&str);
1038
1039
2.40k
  return str.s;
1040
2.40k
}
1041
/* }}} */
1042
1043
1.22k
static zend_always_inline zend_string *func_filename(const zend_function *fn) {
1044
1.22k
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
1045
1.22k
}
1046
1047
1.22k
static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
1048
1.22k
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
1049
1.22k
}
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
1.20k
    inheritance_status status) {
1055
1.20k
  zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
1056
1.20k
  zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
1057
1.20k
  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
163
    const zend_string *unresolved_class = NULL;
1061
163
    ZEND_HASH_MAP_FOREACH_STR_KEY(CG(delayed_autoloads), unresolved_class) {
1062
163
      break;
1063
489
    } ZEND_HASH_FOREACH_END();
1064
163
    ZEND_ASSERT(unresolved_class);
1065
1066
163
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1067
163
      "Could not check compatibility between %s and %s, because class %s is not available",
1068
163
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
1069
1.03k
  } else if (status == INHERITANCE_WARNING) {
1070
298
    const zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
1071
298
      child->common.attributes,
1072
298
      "returntypewillchange",
1073
298
      sizeof("returntypewillchange")-1
1074
298
    );
1075
1076
298
    if (!return_type_will_change_attribute) {
1077
274
      zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1078
274
        "Return type of %s should either be compatible with %s, "
1079
274
        "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1080
274
        ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1081
274
      ZEND_ASSERT(!EG(exception));
1082
274
    }
1083
739
  } else {
1084
739
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1085
739
      "Declaration of %s must be compatible with %s",
1086
739
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1087
739
  }
1088
1.20k
  zend_string_efree(child_prototype);
1089
1.20k
  zend_string_efree(parent_prototype);
1090
1.20k
}
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
13.5k
{
1097
13.5k
  inheritance_status status =
1098
13.5k
    zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1099
13.5k
  if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
1100
1.30k
    if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
1101
284
      add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1102
1.01k
    } else {
1103
1.01k
      ZEND_ASSERT(status == INHERITANCE_ERROR || status == INHERITANCE_WARNING);
1104
1.01k
      emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1105
1.01k
    }
1106
1.30k
  }
1107
13.5k
}
1108
1109
26.9k
#define ZEND_INHERITANCE_LAZY_CHILD_CLONE     (1<<0)
1110
20.1k
#define ZEND_INHERITANCE_CHECK_SILENT         (1<<1) /* don't throw errors */
1111
88.2k
#define ZEND_INHERITANCE_CHECK_PROTO          (1<<2) /* check method prototype (it might be already checked before) */
1112
31.6k
#define ZEND_INHERITANCE_CHECK_VISIBILITY     (1<<3)
1113
25.8k
#define ZEND_INHERITANCE_SET_CHILD_CHANGED    (1<<4)
1114
30.7k
#define ZEND_INHERITANCE_SET_CHILD_PROTO      (1<<5)
1115
28.3k
#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
19.2k
{
1122
19.2k
  uint32_t child_flags;
1123
19.2k
  uint32_t parent_flags = parent->common.fn_flags;
1124
19.2k
  zend_function *proto;
1125
1126
19.2k
#define SEPARATE_METHOD() do { \
1127
14.1k
      if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1128
14.1k
       && 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
14.1k
       && !(child_scope->ce_flags & ZEND_ACC_TRAIT) \
1133
14.1k
       && child->type == ZEND_USER_FUNCTION) { \
1134
        /* op_array wasn't duplicated yet */ \
1135
17
        zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); \
1136
17
        memcpy(new_function, child, sizeof(zend_op_array)); \
1137
17
        Z_PTR_P(child_zv) = child = new_function; \
1138
17
        flags &= ~ZEND_INHERITANCE_LAZY_CHILD_CLONE; \
1139
17
      } \
1140
14.1k
    } while(0)
1141
1142
19.2k
  if (UNEXPECTED((parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_ABSTRACT|ZEND_ACC_CTOR)) == ZEND_ACC_PRIVATE)) {
1143
387
    if (flags & ZEND_INHERITANCE_SET_CHILD_CHANGED) {
1144
172
      SEPARATE_METHOD();
1145
172
      child->common.fn_flags |= ZEND_ACC_CHANGED;
1146
172
    }
1147
    /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
1148
387
    return INHERITANCE_SUCCESS;
1149
387
  }
1150
1151
18.8k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO) && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
1152
26
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1153
12
      return INHERITANCE_ERROR;
1154
12
    }
1155
14
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1156
14
      "Cannot override final method %s::%s()",
1157
14
      ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
1158
26
  }
1159
1160
18.8k
  child_flags = child->common.fn_flags;
1161
  /* You cannot change from static to non static and vice versa.
1162
   */
1163
18.8k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1164
17.3k
   && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
1165
25
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1166
13
      return INHERITANCE_ERROR;
1167
13
    }
1168
12
    if (child_flags & ZEND_ACC_STATIC) {
1169
5
      zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1170
5
        "Cannot make non static method %s::%s() static in class %s",
1171
5
        ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1172
7
    } else {
1173
7
      zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1174
7
        "Cannot make static method %s::%s() non static in class %s",
1175
7
        ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1176
7
    }
1177
12
  }
1178
1179
  /* Disallow making an inherited method abstract. */
1180
18.7k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1181
17.3k
   && 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
18.7k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_CHANGED)
1191
4.74k
   && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
1192
7
    SEPARATE_METHOD();
1193
7
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1194
7
  }
1195
1196
18.7k
  proto = parent->common.prototype ?
1197
17.8k
    parent->common.prototype : parent;
1198
1199
18.7k
  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
1.19k
    if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1203
979
      return INHERITANCE_SUCCESS;
1204
979
    }
1205
211
    parent = proto;
1206
211
  }
1207
1208
17.8k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_PROTO)
1209
14.4k
   && child->common.prototype != proto) {
1210
13.8k
    SEPARATE_METHOD();
1211
13.8k
    child->common.prototype = proto;
1212
13.8k
  }
1213
1214
  /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1215
17.8k
  if ((flags & ZEND_INHERITANCE_CHECK_VISIBILITY)
1216
16.3k
      && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1217
70
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1218
51
      return INHERITANCE_ERROR;
1219
51
    }
1220
19
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1221
19
      "Access level to %s::%s() must be %s (as in class %s)%s",
1222
19
      ZEND_FN_SCOPE_NAME(child), ZSTR_VAL(child->common.function_name), zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1223
70
  }
1224
1225
17.7k
  if (flags & ZEND_INHERITANCE_CHECK_PROTO) {
1226
16.5k
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1227
2.95k
      return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1228
2.95k
    }
1229
13.5k
    perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1230
13.5k
  }
1231
1232
14.7k
  if ((flags & ZEND_INHERITANCE_RESET_CHILD_OVERRIDE)
1233
14.0k
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1234
79
    SEPARATE_METHOD();
1235
79
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1236
79
  }
1237
1238
14.7k
#undef SEPARATE_METHOD
1239
1240
14.7k
  return INHERITANCE_SUCCESS;
1241
17.7k
}
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
54.3k
{
1246
54.3k
  zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1247
1248
54.3k
  if (child) {
1249
14.9k
    zend_function *func = (zend_function*)Z_PTR_P(child);
1250
1251
14.9k
    if (is_interface && UNEXPECTED(func == parent)) {
1252
      /* The same method in interface may be inherited few times */
1253
0
      return;
1254
0
    }
1255
1256
14.9k
    do_inheritance_check_on_method(
1257
14.9k
      func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1258
39.4k
  } else {
1259
1260
39.4k
    if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1261
659
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1262
659
    }
1263
1264
39.4k
    parent = zend_duplicate_function(parent, ce);
1265
1266
39.4k
    if (!is_interface) {
1267
38.8k
      _zend_hash_append_ptr(&ce->function_table, key, parent);
1268
38.8k
    } else {
1269
620
      zend_hash_add_new_ptr(&ce->function_table, key, parent);
1270
620
    }
1271
39.4k
  }
1272
54.3k
}
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.30k
    prop_variance variance) {
1278
3.30k
  if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
1279
2.62k
      && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1280
1.38k
    return INHERITANCE_SUCCESS;
1281
1.38k
  }
1282
1283
1.92k
  if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1284
15
    return INHERITANCE_ERROR;
1285
15
  }
1286
1287
  /* Perform a covariant type check in both directions to determined invariance. */
1288
1.91k
  inheritance_status status1 = variance == PROP_CONTRAVARIANT ? INHERITANCE_SUCCESS :
1289
1.91k
    zend_perform_covariant_type_check(
1290
1.80k
      child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1291
1.91k
  inheritance_status status2 = variance == PROP_COVARIANT ? INHERITANCE_SUCCESS :
1292
1.91k
    zend_perform_covariant_type_check(
1293
1.82k
      parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1294
1.91k
  if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1295
810
    return INHERITANCE_SUCCESS;
1296
810
  }
1297
1.10k
  if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1298
569
    return INHERITANCE_ERROR;
1299
569
  }
1300
533
  ZEND_ASSERT(status1 == INHERITANCE_UNRESOLVED || status2 == INHERITANCE_UNRESOLVED);
1301
533
  return INHERITANCE_UNRESOLVED;
1302
533
}
1303
1304
static ZEND_COLD void emit_incompatible_property_error(
1305
163
    const zend_property_info *child, const zend_property_info *parent, prop_variance variance) {
1306
163
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1307
163
  zend_error_noreturn(E_COMPILE_ERROR,
1308
163
    "Type of %s::$%s must be %s%s (as in class %s)",
1309
163
    ZSTR_VAL(child->ce->name),
1310
163
    zend_get_unmangled_property_name(child->name),
1311
163
    variance == PROP_INVARIANT ? "" :
1312
163
    variance == PROP_COVARIANT ? "subtype of " : "supertype of ",
1313
163
    ZSTR_VAL(type_str),
1314
163
    ZSTR_VAL(parent->ce->name));
1315
163
}
1316
1317
static ZEND_COLD void emit_set_hook_type_error(const zend_property_info *child, const zend_property_info *parent)
1318
4
{
1319
4
  zend_type set_type = parent->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1320
4
  zend_string *type_str = zend_type_to_string_resolved(set_type, parent->ce);
1321
4
  zend_error_noreturn(E_COMPILE_ERROR,
1322
4
    "Set type of %s::$%s must be supertype of %s (as in %s %s)",
1323
4
    ZSTR_VAL(child->ce->name),
1324
4
    zend_get_unmangled_property_name(child->name),
1325
4
    ZSTR_VAL(type_str),
1326
4
    zend_get_object_type_case(parent->ce, false),
1327
4
    ZSTR_VAL(parent->ce->name));
1328
4
}
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.30k
) {
1337
3.30k
  inheritance_status result = full_property_types_compatible(parent_info, child_info, variance);
1338
3.30k
  if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1339
163
    emit_incompatible_property_error(child_info, parent_info, variance);
1340
163
  }
1341
3.30k
  if (result != INHERITANCE_SUCCESS) {
1342
954
    return result;
1343
954
  }
1344
2.35k
  if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1345
258
    ZEND_ASSERT(parent_info->hooks);
1346
258
    if (parent_info->hooks[ZEND_PROPERTY_HOOK_SET]
1347
140
     && (!child_info->hooks || !child_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1348
81
      zend_type set_type = parent_info->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1349
81
      inheritance_status result = zend_perform_covariant_type_check(
1350
81
        parent_info->ce, set_type, child_info->ce, child_info->type);
1351
81
      if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1352
4
        emit_set_hook_type_error(child_info, parent_info);
1353
4
      }
1354
81
    }
1355
258
  }
1356
2.35k
  return INHERITANCE_SUCCESS;
1357
2.35k
}
1358
1359
static bool property_has_operation(const zend_property_info *prop_info, zend_property_hook_kind kind)
1360
218
{
1361
218
  return (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1362
199
      && (kind == ZEND_PROPERTY_HOOK_GET || !(prop_info->flags & ZEND_ACC_READONLY)))
1363
32
    || (prop_info->hooks && prop_info->hooks[kind]);
1364
218
}
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
2.18k
) {
1372
2.18k
  zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
1373
2.18k
  zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;
1374
1375
2.18k
  if (child
1376
1.03k
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)
1377
38
   && property_has_operation(parent_info, kind)) {
1378
28
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1379
28
  }
1380
1381
2.18k
  if (!parent) {
1382
1.30k
    return;
1383
1.30k
  }
1384
1385
876
  if (!child) {
1386
312
    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
180
      if (property_has_operation(child_info, kind)) {
1389
162
        return;
1390
162
      }
1391
18
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1392
18
    }
1393
150
    if (!child_info->hooks) {
1394
89
      ce->num_hooked_props++;
1395
89
      child_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1396
89
      memset(child_info->hooks, 0, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1397
89
    }
1398
150
    child_info->hooks[kind] = zend_duplicate_function(parent, ce);
1399
150
    return;
1400
312
  }
1401
1402
564
  child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1403
1404
564
  uint32_t parent_flags = parent->common.fn_flags;
1405
564
  if (parent_flags & ZEND_ACC_PRIVATE) {
1406
0
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1407
0
    return;
1408
0
  }
1409
1410
564
  if (parent_flags & ZEND_ACC_FINAL) {
1411
7
    zend_error_noreturn(E_COMPILE_ERROR,
1412
7
      "Cannot override final property hook %s::%s()",
1413
7
      ZSTR_VAL(parent->common.scope->name),
1414
7
      ZSTR_VAL(parent->common.function_name));
1415
7
  }
1416
1417
557
  do_inheritance_check_on_method(
1418
557
    child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
1419
557
    ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY
1420
557
      | ZEND_INHERITANCE_SET_CHILD_CHANGED | ZEND_INHERITANCE_SET_CHILD_PROTO
1421
557
      | 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
557
}
1427
1428
3.96k
static prop_variance prop_get_variance(const zend_property_info *prop_info) {
1429
3.96k
  bool unbacked = prop_info->flags & ZEND_ACC_VIRTUAL;
1430
3.96k
  if (unbacked && prop_info->hooks) {
1431
832
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1432
500
      return PROP_COVARIANT;
1433
500
    }
1434
332
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
1435
141
      return PROP_CONTRAVARIANT;
1436
141
    }
1437
332
  }
1438
3.32k
  return PROP_INVARIANT;
1439
3.96k
}
1440
1441
static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1442
13.5k
{
1443
13.5k
  zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1444
1445
13.5k
  if (UNEXPECTED(child)) {
1446
2.31k
    zend_property_info *child_info = Z_PTR_P(child);
1447
2.31k
    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1448
378
      child_info->flags |= ZEND_ACC_CHANGED;
1449
378
    }
1450
2.31k
    if (parent_info->flags & ZEND_ACC_FINAL) {
1451
20
      zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final property %s::$%s",
1452
20
        ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key));
1453
20
    }
1454
2.29k
    if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1455
1.92k
      if (!(parent_info->ce->ce_flags & ZEND_ACC_INTERFACE)) {
1456
1.83k
        child_info->prototype = parent_info->prototype;
1457
1.83k
      }
1458
1459
1.92k
      if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
1460
5
        zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1461
5
          (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1462
5
          (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
1463
5
      }
1464
1.91k
      if (UNEXPECTED((child_info->flags & ZEND_ACC_READONLY) != (parent_info->flags & ZEND_ACC_READONLY))) {
1465
40
        if (!(parent_info->flags & ZEND_ACC_ABSTRACT)) {
1466
6
          zend_error_noreturn(E_COMPILE_ERROR,
1467
6
            "Cannot redeclare %s property %s::$%s as %s %s::$%s",
1468
6
            parent_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1469
6
            ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1470
6
            child_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1471
6
            ZSTR_VAL(ce->name), ZSTR_VAL(key));
1472
6
        }
1473
40
      }
1474
1.91k
      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
149
       && !(parent_info->hooks && (parent_info->flags & ZEND_ACC_VIRTUAL) && !parent_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1477
98
        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
98
        if (!parent_set_visibility) {
1481
35
          parent_set_visibility = zend_visibility_to_set_visibility(parent_info->flags & ZEND_ACC_PPP_MASK);
1482
35
        }
1483
98
        uint32_t child_set_visibility = child_info->flags & ZEND_ACC_PPP_SET_MASK;
1484
98
        if (child_set_visibility > parent_set_visibility) {
1485
34
          zend_error_noreturn(
1486
34
            E_COMPILE_ERROR,
1487
34
            "Set access level of %s::$%s must be %s (as in class %s)%s",
1488
34
            ZSTR_VAL(ce->name), ZSTR_VAL(key),
1489
34
            zend_asymmetric_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name),
1490
34
            !(parent_info->flags & ZEND_ACC_PPP_SET_MASK) ? "" : " or weaker");
1491
34
        }
1492
98
      }
1493
1494
1.87k
      if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1495
7
        zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ZSTR_VAL(ce->name), ZSTR_VAL(key), zend_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name), (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1496
7
      }
1497
1.87k
      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
1.12k
        bool use_child_prop = !parent_info->hooks && child_info->hooks;
1502
1503
1.12k
        if (use_child_prop && child_info->offset == ZEND_VIRTUAL_PROPERTY_OFFSET) {
1504
207
          child_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
1505
207
          ce->default_properties_count++;
1506
207
          ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1507
207
          zval *property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(child_info->offset)];
1508
207
          ZVAL_UNDEF(property_default_ptr);
1509
207
          Z_PROP_FLAG_P(property_default_ptr) = IS_PROP_UNINIT;
1510
207
        }
1511
1512
1.12k
        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
1.12k
        zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1515
1.12k
        if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1516
1.00k
          if (use_child_prop) {
1517
365
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1518
644
          } else {
1519
644
            int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1520
644
            ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1521
644
            ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1522
644
          }
1523
1.00k
        } else {
1524
          /* Default value was removed in child, remove it from parent too. */
1525
116
          if (ZEND_TYPE_IS_SET(child_info->type)) {
1526
64
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1527
64
          } else {
1528
52
            ZVAL_NULL(&ce->default_properties_table[parent_num]);
1529
52
          }
1530
116
        }
1531
1532
1.12k
        if (!use_child_prop) {
1533
760
          child_info->offset = parent_info->offset;
1534
760
        }
1535
1.12k
        child_info->flags &= ~ZEND_ACC_VIRTUAL;
1536
1.12k
      }
1537
1538
1.87k
      if (parent_info->hooks || child_info->hooks) {
1539
3.28k
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1540
2.18k
          inherit_property_hook(ce, parent_info, child_info, i);
1541
2.18k
        }
1542
1.10k
      }
1543
1544
1.87k
      prop_variance variance = prop_get_variance(parent_info);
1545
1.87k
      if (ZEND_TYPE_IS_SET(parent_info->type)) {
1546
1.01k
        inheritance_status status = verify_property_type_compatibility(
1547
1.01k
          parent_info, child_info, variance, true, false);
1548
1.01k
        if (status == INHERITANCE_UNRESOLVED) {
1549
59
          add_property_compatibility_obligation(ce, child_info, parent_info, variance);
1550
59
        }
1551
1.01k
      } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1552
12
        zend_error_noreturn(E_COMPILE_ERROR,
1553
12
            "Type of %s::$%s must be omitted to match the parent definition in class %s",
1554
12
            ZSTR_VAL(ce->name),
1555
12
            ZSTR_VAL(key),
1556
12
            ZSTR_VAL(parent_info->ce->name));
1557
12
      }
1558
1559
1.86k
      if (child_info->ce == ce) {
1560
1.67k
        child_info->flags &= ~ZEND_ACC_OVERRIDE;
1561
1.67k
      }
1562
1.86k
    }
1563
11.2k
  } else {
1564
11.2k
    zend_function **hooks = parent_info->hooks;
1565
11.2k
    if (hooks) {
1566
298
      ce->num_hooked_props++;
1567
298
      if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1568
27
        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1569
27
      }
1570
298
    }
1571
1572
11.2k
    _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1573
11.2k
  }
1574
13.5k
}
1575
/* }}} */
1576
1577
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1578
13.1k
{
1579
13.1k
  if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
1580
0
    zend_error_noreturn(E_CORE_ERROR, "%s %s could not implement interface %s", zend_get_object_type_uc(ce), ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1581
0
  }
1582
  /* This should be prevented by the class lookup logic. */
1583
13.1k
  ZEND_ASSERT(ce != iface);
1584
13.1k
}
1585
/* }}} */
1586
1587
static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1588
3.72k
{
1589
  /* expects interface to be contained in ce's interface list already */
1590
3.72k
  uint32_t i, ce_num, if_num = iface->num_interfaces;
1591
1592
3.72k
  ce_num = ce->num_interfaces;
1593
1594
3.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
11.2k
  while (if_num--) {
1598
7.56k
    zend_class_entry *entry = iface->interfaces[if_num];
1599
9.22k
    for (i = 0; i < ce_num; i++) {
1600
2.70k
      if (ce->interfaces[i] == entry) {
1601
1.03k
        break;
1602
1.03k
      }
1603
2.70k
    }
1604
7.56k
    if (i == ce_num) {
1605
6.52k
      ce->interfaces[ce->num_interfaces++] = entry;
1606
6.52k
    }
1607
7.56k
  }
1608
3.72k
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1609
1610
  /* and now call the implementing handlers */
1611
10.2k
  while (ce_num < ce->num_interfaces) {
1612
6.52k
    do_implement_interface(ce, ce->interfaces[ce_num++]);
1613
6.52k
  }
1614
3.72k
}
1615
/* }}} */
1616
1617
static void emit_incompatible_class_constant_error(
1618
16
    const zend_class_constant *child, const zend_class_constant *parent, const zend_string *const_name) {
1619
16
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1620
16
  zend_error_noreturn(E_COMPILE_ERROR,
1621
16
    "Type of %s::%s must be compatible with %s::%s of type %s",
1622
16
    ZSTR_VAL(child->ce->name),
1623
16
    ZSTR_VAL(const_name),
1624
16
    ZSTR_VAL(parent->ce->name),
1625
16
    ZSTR_VAL(const_name),
1626
16
    ZSTR_VAL(type_str));
1627
16
}
1628
1629
static inheritance_status class_constant_types_compatible(const zend_class_constant *parent, const zend_class_constant *child)
1630
332
{
1631
332
  ZEND_ASSERT(ZEND_TYPE_IS_SET(parent->type));
1632
1633
332
  if (!ZEND_TYPE_IS_SET(child->type)) {
1634
8
    return INHERITANCE_ERROR;
1635
8
  }
1636
1637
324
  return zend_perform_covariant_type_check(child->ce, child->type, parent->ce, parent->type);
1638
332
}
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
7.90k
{
1645
7.90k
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1646
7.90k
  zend_class_constant *c;
1647
1648
7.90k
  if (zv != NULL) {
1649
473
    c = (zend_class_constant*)Z_PTR_P(zv);
1650
473
    bool inherit = do_inherit_constant_check(ce, parent_const, name);
1651
473
    ZEND_ASSERT(!inherit);
1652
7.43k
  } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1653
7.41k
    if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1654
235
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1655
235
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1656
235
      if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
1657
36
        c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1658
36
        memcpy(c, parent_const, sizeof(zend_class_constant));
1659
36
        parent_const = c;
1660
36
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1661
36
      }
1662
235
    }
1663
7.41k
    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
7.41k
    _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1669
7.41k
  }
1670
7.90k
}
1671
/* }}} */
1672
1673
void zend_build_properties_info_table(zend_class_entry *ce)
1674
106k
{
1675
106k
  zend_property_info **table, *prop;
1676
106k
  size_t size;
1677
106k
  if (ce->default_properties_count == 0) {
1678
88.8k
    return;
1679
88.8k
  }
1680
1681
17.4k
  ZEND_ASSERT(ce->properties_info_table == NULL);
1682
17.4k
  size = sizeof(zend_property_info *) * ce->default_properties_count;
1683
17.4k
  if (ce->type == ZEND_USER_CLASS) {
1684
16.4k
    ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1685
16.4k
  } 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
17.4k
  memset(table, 0, size);
1691
1692
17.4k
  if (ce->parent && ce->parent->default_properties_count != 0) {
1693
3.28k
    zend_property_info **parent_table = ce->parent->properties_info_table;
1694
3.28k
    memcpy(
1695
3.28k
      table, parent_table,
1696
3.28k
      sizeof(zend_property_info *) * ce->parent->default_properties_count
1697
3.28k
    );
1698
1699
    /* Child did not add any new properties, we are done */
1700
3.28k
    if (ce->default_properties_count == ce->parent->default_properties_count) {
1701
2.16k
      return;
1702
2.16k
    }
1703
3.28k
  }
1704
1705
81.8k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, prop) {
1706
81.8k
    if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0
1707
23.3k
     && !(prop->flags & ZEND_ACC_VIRTUAL)) {
1708
22.7k
      const zend_property_info *root_prop = prop->prototype;
1709
22.7k
      if (UNEXPECTED(root_prop->flags & ZEND_ACC_VIRTUAL)) {
1710
        /* Prototype is virtual, we need to manually hunt down the first backed property. */
1711
126
        root_prop = prop;
1712
126
        zend_class_entry *parent_ce;
1713
143
        while ((parent_ce = root_prop->ce->parent)) {
1714
143
          zend_property_info *parent_prop = zend_hash_find_ptr(&parent_ce->properties_info, key);
1715
143
          if (!parent_prop
1716
143
           || parent_prop->prototype != prop->prototype
1717
143
           || (parent_prop->flags & ZEND_ACC_VIRTUAL)) {
1718
126
            break;
1719
126
          }
1720
17
          root_prop = parent_prop;
1721
17
        }
1722
126
      }
1723
22.7k
      uint32_t prop_table_offset = OBJ_PROP_TO_NUM(root_prop->offset);
1724
22.7k
      table[prop_table_offset] = prop;
1725
22.7k
    }
1726
81.8k
  } ZEND_HASH_FOREACH_END();
1727
15.2k
}
1728
1729
ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name)
1730
3.74k
{
1731
3.74k
  if (!prop_info->hooks) {
1732
0
    return;
1733
0
  }
1734
3.74k
  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
3.74k
  if ((prop_info->flags & ZEND_ACC_VIRTUAL) && prop_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1738
29
    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
29
    } else {
1741
29
      zend_error_noreturn(E_COMPILE_ERROR,
1742
29
        "Cannot specify default value for virtual hooked property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1743
29
    }
1744
29
  }
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
3.71k
  if (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1748
1.51k
   && !ZEND_TYPE_IS_SET(prop_info->type)
1749
947
   && Z_TYPE(ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]) == IS_UNDEF) {
1750
530
    ZVAL_NULL(&ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]);
1751
530
  }
1752
11.1k
  for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1753
7.41k
    const zend_function *func = prop_info->hooks[i];
1754
7.41k
    if (func) {
1755
4.65k
      if ((zend_property_hook_kind)i == ZEND_PROPERTY_HOOK_GET
1756
2.88k
       && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1757
188
       && !(prop_info->flags & ZEND_ACC_VIRTUAL)
1758
34
       && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1759
7
        zend_error_noreturn(E_COMPILE_ERROR, "Get hook of backed property %s::%s with set hook may not return by reference",
1760
7
          ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1761
7
      }
1762
4.65k
      if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
1763
643
        abstract_error = false;
1764
643
      }
1765
4.65k
    }
1766
7.41k
  }
1767
3.70k
  if (abstract_error) {
1768
5
    zend_error_noreturn(E_COMPILE_ERROR,
1769
5
      "Abstract property %s::$%s must specify at least one abstract hook", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1770
5
  }
1771
3.70k
  if ((prop_info->flags & ZEND_ACC_VIRTUAL)
1772
2.19k
   && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)
1773
70
   && (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET] || !prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1774
13
    const char *prefix = !prop_info->hooks[ZEND_PROPERTY_HOOK_GET]
1775
13
      ? "set-only" : "get-only";
1776
13
    zend_error_noreturn(E_COMPILE_ERROR,
1777
13
      "%s virtual property %s::$%s must not specify asymmetric visibility",
1778
13
      prefix, ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1779
13
  }
1780
3.70k
}
1781
1782
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name)
1783
24
{
1784
24
  zend_error_noreturn(E_COMPILE_ERROR, "Type of parameter $%s of hook %s::$%s::set must be compatible with property type",
1785
24
    ZSTR_VAL(value_param_name), ZSTR_VAL(class_name), zend_get_unmangled_property_name(prop_name));
1786
24
}
1787
1788
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info)
1789
19
{
1790
19
  zend_string *value_param_name = prop_info->hooks[ZEND_PROPERTY_HOOK_SET]->op_array.arg_info[0].name;
1791
19
  zend_hooked_property_variance_error_ex(value_param_name, prop_info->ce->name, prop_info->name);
1792
19
}
1793
1794
ZEND_API inheritance_status zend_verify_property_hook_variance(const zend_property_info *prop_info, const zend_function *func)
1795
1.88k
{
1796
1.88k
  ZEND_ASSERT(prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET] == func);
1797
1798
1.88k
  zend_arg_info *value_arg_info = &func->op_array.arg_info[0];
1799
1.88k
  if (!ZEND_TYPE_IS_SET(value_arg_info->type)) {
1800
1.08k
    return INHERITANCE_SUCCESS;
1801
1.08k
  }
1802
1803
805
  if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1804
0
    return INHERITANCE_ERROR;
1805
0
  }
1806
1807
805
  zend_class_entry *ce = prop_info->ce;
1808
805
  return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type);
1809
805
}
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
8.94k
{
1834
8.94k
  zend_property_info *property_info;
1835
8.94k
  zend_string *key;
1836
1837
8.94k
  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
8.94k
  } 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
28
    if (parent_ce->ce_flags & ZEND_ACC_ENUM) {
1846
12
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend enum %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1847
12
    }
1848
    /* Class must not extend a final class */
1849
16
    if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1850
11
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1851
11
    }
1852
1853
    /* Class declaration must not extend traits or interfaces */
1854
5
    if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1855
5
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1856
5
        ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1857
5
      );
1858
5
    }
1859
5
  }
1860
1861
8.91k
  if (UNEXPECTED((ce->ce_flags & ZEND_ACC_READONLY_CLASS) != (parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS))) {
1862
9
    zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1863
9
      ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1864
9
      parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1865
9
    );
1866
9
  }
1867
1868
8.90k
  if (ce->parent_name) {
1869
7.44k
    zend_string_release_ex(ce->parent_name, 0);
1870
7.44k
  }
1871
8.90k
  ce->parent = parent_ce;
1872
8.90k
  ce->default_object_handlers = parent_ce->default_object_handlers;
1873
8.90k
  ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1874
1875
  /* Inherit properties */
1876
8.90k
  if (parent_ce->default_properties_count) {
1877
3.46k
    zval *src, *dst, *end;
1878
1879
3.46k
    if (ce->default_properties_count) {
1880
1.15k
      zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1881
1.15k
      src = ce->default_properties_table + ce->default_properties_count;
1882
1.15k
      end = table + parent_ce->default_properties_count;
1883
1.15k
      dst = end + ce->default_properties_count;
1884
1.15k
      ce->default_properties_table = table;
1885
1.57k
      do {
1886
1.57k
        dst--;
1887
1.57k
        src--;
1888
1.57k
        ZVAL_COPY_VALUE_PROP(dst, src);
1889
1.57k
      } while (dst != end);
1890
1.15k
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1891
1.15k
      end = ce->default_properties_table;
1892
2.31k
    } else {
1893
2.31k
      end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1894
2.31k
      dst = end + parent_ce->default_properties_count;
1895
2.31k
      ce->default_properties_table = end;
1896
2.31k
    }
1897
3.46k
    src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1898
3.46k
    if (UNEXPECTED(parent_ce->type != ce->type)) {
1899
      /* User class extends internal */
1900
1.87k
      do {
1901
1.87k
        dst--;
1902
1.87k
        src--;
1903
        /* We don't have to account for refcounting because
1904
         * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1905
1.87k
        ZEND_ASSERT(!Z_REFCOUNTED_P(src));
1906
1.87k
        ZVAL_COPY_VALUE_PROP(dst, src);
1907
1.87k
        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
1.87k
        continue;
1912
1.87k
      } while (dst != end);
1913
3.15k
    } else {
1914
9.91k
      do {
1915
9.91k
        dst--;
1916
9.91k
        src--;
1917
9.91k
        ZVAL_COPY_PROP(dst, src);
1918
9.91k
        if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1919
119
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1920
119
          ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1921
119
        }
1922
9.91k
        continue;
1923
9.91k
      } while (dst != end);
1924
3.15k
    }
1925
3.46k
    ce->default_properties_count += parent_ce->default_properties_count;
1926
3.46k
  }
1927
1928
8.90k
  if (parent_ce->default_static_members_count) {
1929
412
    zval *src, *dst, *end;
1930
1931
412
    if (ce->default_static_members_count) {
1932
210
      zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1933
210
      src = ce->default_static_members_table + ce->default_static_members_count;
1934
210
      end = table + parent_ce->default_static_members_count;
1935
210
      dst = end + ce->default_static_members_count;
1936
210
      ce->default_static_members_table = table;
1937
376
      do {
1938
376
        dst--;
1939
376
        src--;
1940
376
        ZVAL_COPY_VALUE(dst, src);
1941
376
      } while (dst != end);
1942
210
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1943
210
      end = ce->default_static_members_table;
1944
210
    } else {
1945
202
      end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1946
202
      dst = end + parent_ce->default_static_members_count;
1947
202
      ce->default_static_members_table = end;
1948
202
    }
1949
412
    src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1950
745
    do {
1951
745
      dst--;
1952
745
      src--;
1953
745
      if (Z_TYPE_P(src) == IS_INDIRECT) {
1954
44
        ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1955
701
      } else {
1956
701
        ZVAL_INDIRECT(dst, src);
1957
701
      }
1958
745
      if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1959
53
        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1960
53
        ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
1961
53
      }
1962
745
    } while (dst != end);
1963
412
    ce->default_static_members_count += parent_ce->default_static_members_count;
1964
412
    if (!ZEND_MAP_PTR(ce->static_members_table)) {
1965
412
      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
412
    }
1970
412
  }
1971
1972
24.9k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1973
24.9k
    if (property_info->ce == ce) {
1974
3.57k
      if (property_info->flags & ZEND_ACC_STATIC) {
1975
534
        property_info->offset += parent_ce->default_static_members_count;
1976
3.04k
      } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1977
2.16k
        property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1978
2.16k
      }
1979
3.57k
    }
1980
24.9k
  } ZEND_HASH_FOREACH_END();
1981
1982
8.90k
  if (zend_hash_num_elements(&parent_ce->properties_info)) {
1983
4.12k
    zend_hash_extend(&ce->properties_info,
1984
4.12k
      zend_hash_num_elements(&ce->properties_info) +
1985
4.12k
      zend_hash_num_elements(&parent_ce->properties_info), 0);
1986
1987
35.0k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1988
35.0k
      do_inherit_property(property_info, key, ce);
1989
35.0k
    } ZEND_HASH_FOREACH_END();
1990
4.12k
  }
1991
1992
8.90k
  if (ce->num_hooked_props) {
1993
5.72k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
1994
5.72k
      if (property_info->ce == ce && property_info->hooks) {
1995
1.13k
        zend_verify_hooked_property(ce, property_info, key);
1996
1.13k
      }
1997
5.72k
    } ZEND_HASH_FOREACH_END();
1998
774
  }
1999
2000
8.90k
  if (zend_hash_num_elements(&parent_ce->constants_table)) {
2001
1.48k
    zend_class_constant *c;
2002
2003
1.48k
    zend_hash_extend(&ce->constants_table,
2004
1.48k
      zend_hash_num_elements(&ce->constants_table) +
2005
1.48k
      zend_hash_num_elements(&parent_ce->constants_table), 0);
2006
2007
18.7k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
2008
18.7k
      do_inherit_class_constant(key, c, ce);
2009
18.7k
    } ZEND_HASH_FOREACH_END();
2010
1.48k
  }
2011
2012
8.90k
  if (zend_hash_num_elements(&parent_ce->function_table)) {
2013
6.14k
    zend_hash_extend(&ce->function_table,
2014
6.14k
      zend_hash_num_elements(&ce->function_table) +
2015
6.14k
      zend_hash_num_elements(&parent_ce->function_table), 0);
2016
6.14k
    uint32_t flags =
2017
6.14k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2018
6.14k
      ZEND_INHERITANCE_SET_CHILD_CHANGED |
2019
6.14k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2020
6.14k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2021
2022
6.14k
    if (!checked) {
2023
3.08k
      flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2024
3.08k
    }
2025
6.14k
    zend_function *func;
2026
98.6k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
2027
98.6k
      do_inherit_method(key, func, ce, false, flags);
2028
98.6k
    } ZEND_HASH_FOREACH_END();
2029
6.14k
  }
2030
2031
8.90k
  do_inherit_parent_constructor(ce);
2032
2033
8.90k
  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
8.90k
  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
8.90k
}
2044
/* }}} */
2045
2046
static zend_always_inline bool check_trait_property_or_constant_value_compatibility(zend_class_entry *ce, zval *op1, zval *op2) /* {{{ */
2047
179
{
2048
179
  bool is_compatible;
2049
179
  zval op1_tmp, op2_tmp;
2050
2051
  /* if any of the values is a constant, we try to resolve it */
2052
179
  if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
2053
35
    ZVAL_COPY_OR_DUP(&op1_tmp, op1);
2054
35
    if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
2055
6
      zval_ptr_dtor(&op1_tmp);
2056
6
      return false;
2057
6
    }
2058
29
    op1 = &op1_tmp;
2059
29
  }
2060
173
  if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
2061
26
    ZVAL_COPY_OR_DUP(&op2_tmp, op2);
2062
26
    if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
2063
1
      zval_ptr_dtor(&op2_tmp);
2064
1
      return false;
2065
1
    }
2066
25
    op2 = &op2_tmp;
2067
25
  }
2068
2069
172
  is_compatible = fast_is_identical_function(op1, op2);
2070
2071
172
  if (op1 == &op1_tmp) {
2072
28
    zval_ptr_dtor_nogc(&op1_tmp);
2073
28
  }
2074
172
  if (op2 == &op2_tmp) {
2075
25
    zval_ptr_dtor_nogc(&op2_tmp);
2076
25
  }
2077
2078
172
  return is_compatible;
2079
173
}
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
1.26k
) {
2086
1.26k
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2087
1.26k
  if (zv == NULL) {
2088
678
    return true;
2089
678
  }
2090
2091
588
  zend_class_constant *child_constant = Z_PTR_P(zv);
2092
588
  if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
2093
10
    zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
2094
10
      ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2095
10
      ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
2096
10
    );
2097
10
  }
2098
2099
578
  if (child_constant->ce != parent_constant->ce && child_constant->ce != ce) {
2100
17
    zend_error_noreturn(E_COMPILE_ERROR,
2101
17
      "%s %s inherits both %s::%s and %s::%s, which is ambiguous",
2102
17
      zend_get_object_type_uc(ce),
2103
17
      ZSTR_VAL(ce->name),
2104
17
      ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2105
17
      ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
2106
17
  }
2107
2108
561
  if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(child_constant) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PPP_MASK))) {
2109
4
    zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in %s %s)%s",
2110
4
      ZSTR_VAL(ce->name), ZSTR_VAL(name),
2111
4
      zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_constant)),
2112
4
      zend_get_object_type(parent_constant->ce),
2113
4
      ZSTR_VAL(parent_constant->ce->name),
2114
4
      (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PUBLIC) ? "" : " or weaker"
2115
4
    );
2116
4
  }
2117
2118
557
  if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE)) {
2119
538
    if (child_constant->ce == ce) {
2120
518
      ZEND_CLASS_CONST_FLAGS(child_constant) &= ~ZEND_ACC_OVERRIDE;
2121
518
    }
2122
538
  }
2123
2124
557
  if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
2125
113
    inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
2126
113
    if (status == INHERITANCE_ERROR) {
2127
12
      emit_incompatible_class_constant_error(child_constant, parent_constant, name);
2128
101
    } else if (status == INHERITANCE_UNRESOLVED) {
2129
4
      add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
2130
4
    }
2131
113
  }
2132
2133
557
  return false;
2134
561
}
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
773
{
2139
773
  if (do_inherit_constant_check(ce, c, name)) {
2140
678
    zend_class_constant *ct;
2141
678
    if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2142
28
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2143
28
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2144
28
      if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
2145
27
        ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2146
27
        memcpy(ct, c, sizeof(zend_class_constant));
2147
27
        c = ct;
2148
27
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2149
27
      }
2150
28
    }
2151
678
    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
678
    zend_hash_update_ptr(&ce->constants_table, name, c);
2157
678
  }
2158
773
}
2159
/* }}} */
2160
2161
static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2162
6.67k
{
2163
6.67k
  zend_function *func;
2164
6.67k
  zend_string *key;
2165
6.67k
  zend_class_constant *c;
2166
6.67k
  uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2167
2168
6.67k
  if (iface->num_interfaces) {
2169
1.56k
    zend_do_inherit_interfaces(ce, iface);
2170
1.56k
  }
2171
2172
6.67k
  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
6.23k
    flags |=
2176
6.23k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2177
6.23k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2178
6.23k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2179
6.23k
  } else {
2180
437
    flags |=
2181
437
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2182
437
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2183
437
  }
2184
2185
14.8k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2186
14.8k
    do_inherit_iface_constant(key, c, ce, iface);
2187
14.8k
  } ZEND_HASH_FOREACH_END();
2188
2189
35.6k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2190
35.6k
    do_inherit_method(key, func, ce, true, flags);
2191
35.6k
  } ZEND_HASH_FOREACH_END();
2192
2193
6.67k
  zend_hash_extend(&ce->properties_info,
2194
6.64k
    zend_hash_num_elements(&ce->properties_info) +
2195
6.64k
    zend_hash_num_elements(&iface->properties_info), 0);
2196
2197
6.64k
  zend_property_info *prop;
2198
6.84k
  ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2199
6.84k
    do_inherit_property(prop, key, ce);
2200
6.84k
  } ZEND_HASH_FOREACH_END();
2201
2202
6.64k
  do_implement_interface(ce, iface);
2203
6.64k
}
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
4.06k
{
2246
4.06k
  uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2247
4.06k
  uint32_t num_interfaces = num_parent_interfaces;
2248
4.06k
  zend_string *key;
2249
4.06k
  zend_class_constant *c;
2250
4.06k
  uint32_t i;
2251
2252
9.14k
  for (i = 0; i < ce->num_interfaces; i++) {
2253
5.10k
    zend_class_entry *iface = interfaces[num_parent_interfaces + i];
2254
5.10k
    if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2255
0
      add_dependency_obligation(ce, iface);
2256
0
    }
2257
5.10k
    if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
2258
13
      efree(interfaces);
2259
13
      zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2260
13
    }
2261
6.26k
    for (uint32_t j = 0; j < num_interfaces; j++) {
2262
1.24k
      if (interfaces[j] == iface) {
2263
71
        if (j >= num_parent_interfaces) {
2264
20
          efree(interfaces);
2265
20
          zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
2266
20
            zend_get_object_type_uc(ce),
2267
20
            ZSTR_VAL(ce->name),
2268
20
            ZSTR_VAL(iface->name));
2269
20
        }
2270
        /* skip duplications */
2271
142
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2272
142
          do_inherit_constant_check(ce, c, key);
2273
142
        } ZEND_HASH_FOREACH_END();
2274
2275
51
        iface = NULL;
2276
51
        break;
2277
51
      }
2278
1.24k
    }
2279
5.07k
    if (iface) {
2280
5.02k
      interfaces[num_interfaces] = iface;
2281
5.02k
      num_interfaces++;
2282
5.02k
    }
2283
5.07k
  }
2284
2285
4.03k
  if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2286
1.05k
    for (i = 0; i < ce->num_interfaces; i++) {
2287
590
      zend_string_release_ex(ce->interface_names[i].name, 0);
2288
590
      zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2289
590
    }
2290
467
    efree(ce->interface_names);
2291
467
  }
2292
2293
4.03k
  ce->num_interfaces = num_interfaces;
2294
4.03k
  ce->interfaces = interfaces;
2295
4.03k
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2296
2297
4.18k
  for (i = 0; i < num_parent_interfaces; i++) {
2298
144
    do_implement_interface(ce, ce->interfaces[i]);
2299
144
  }
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
9.00k
  for (; i < num_interfaces; i++) {
2303
4.97k
    do_interface_implementation(ce, ce->interfaces[i]);
2304
4.97k
  }
2305
4.03k
}
2306
/* }}} */
2307
2308
2309
void zend_inheritance_check_override(const zend_class_entry *ce)
2310
104k
{
2311
104k
  if (ce->ce_flags & ZEND_ACC_TRAIT) {
2312
3.52k
    return;
2313
3.52k
  }
2314
2315
359k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *f) {
2316
359k
    if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2317
28
      ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2318
2319
28
      zend_error_at_noreturn(
2320
28
        E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2321
28
        "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2322
28
        ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2323
28
    }
2324
359k
  } ZEND_HASH_FOREACH_END();
2325
2326
230k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->constants_table, zend_string *name, zend_class_constant *c) {
2327
230k
    if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_OVERRIDE) {
2328
46
      zend_error_noreturn(
2329
46
        E_COMPILE_ERROR,
2330
46
        "%s::%s has #[\\Override] attribute, but no matching parent constant exists",
2331
46
        ZSTR_VAL(ce->name), ZSTR_VAL(name));
2332
46
    }
2333
230k
  } ZEND_HASH_FOREACH_END();
2334
2335
269k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
2336
269k
    if (prop->flags & ZEND_ACC_OVERRIDE) {
2337
40
      zend_error_noreturn(
2338
40
        E_COMPILE_ERROR,
2339
40
        "%s::$%s has #[\\Override] attribute, but no matching parent property exists",
2340
40
        ZSTR_VAL(ce->name), zend_get_unmangled_property_name(prop->name));
2341
40
    }
2342
2343
33.6k
    if (prop->hooks) {
2344
10.7k
      for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2345
7.19k
        zend_function *f = prop->hooks[i];
2346
7.19k
        if (f && f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2347
16
          ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2348
2349
16
          zend_error_at_noreturn(
2350
16
            E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2351
16
            "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2352
16
            ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2353
16
        }
2354
7.19k
      }
2355
3.60k
    }
2356
33.6k
  } ZEND_HASH_FOREACH_END();
2357
100k
}
2358
2359
2360
static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
2361
434
{
2362
  /* self in trait methods should be resolved to the using class, not the trait. */
2363
434
  return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
2364
434
}
2365
2366
static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
2367
2.08k
{
2368
2.08k
  zend_function *existing_fn = NULL;
2369
2.08k
  zend_function *new_fn;
2370
2371
2.08k
  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
344
    if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
2375
5
      (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
2376
5
      (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2377
5
      return;
2378
5
    }
2379
2380
    /* Abstract method signatures from the trait must be satisfied. */
2381
339
    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
217
      do_inheritance_check_on_method(
2388
217
        existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
2389
217
        ce, NULL, ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
2390
217
      return;
2391
217
    }
2392
2393
122
    if (existing_fn->common.scope == ce) {
2394
      /* members from the current class override trait methods */
2395
86
      return;
2396
86
    } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
2397
36
        && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
2398
      /* two traits can't define the same non-abstract method */
2399
36
      zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
2400
36
        ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
2401
36
        ZSTR_VAL(ce->name), ZSTR_VAL(name),
2402
36
        ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
2403
36
    }
2404
122
  }
2405
2406
1.73k
  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
1.73k
  } 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
1.73k
  } else {
2415
1.73k
    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2416
1.73k
    memcpy(new_fn, fn, sizeof(zend_op_array));
2417
1.73k
    new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2418
1.73k
  }
2419
1.73k
  new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2420
2421
  /* Reassign method name, in case it is an alias. */
2422
1.73k
  new_fn->common.function_name = name;
2423
1.73k
  function_add_ref(new_fn);
2424
1.73k
  fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2425
1.73k
  zend_add_magic_method(ce, fn, key);
2426
1.73k
}
2427
/* }}} */
2428
2429
static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2430
2.35k
{
2431
2.35k
  if (fn->common.scope->ce_flags & ZEND_ACC_TRAIT) {
2432
2433
1.69k
    fn->common.scope = ce;
2434
2435
1.69k
    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2436
29
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2437
29
    }
2438
1.69k
    if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2439
61
      ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2440
61
    }
2441
1.69k
  }
2442
2.35k
}
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
2.08k
{
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
2.08k
  if (!(original_fn_flags & ZEND_ACC_FINAL)
2452
1.98k
    && (fn_copy->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2453
14
    && !zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2454
14
    zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2455
14
  }
2456
2.08k
}
2457
2458
static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
2459
1.86k
{
2460
1.86k
  zend_trait_alias  *alias, **alias_ptr;
2461
1.86k
  zend_function      fn_copy;
2462
1.86k
  int                i;
2463
2464
  /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2465
1.86k
  if (ce->trait_aliases) {
2466
409
    alias_ptr = ce->trait_aliases;
2467
409
    alias = *alias_ptr;
2468
409
    i = 0;
2469
1.82k
    while (alias) {
2470
      /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2471
1.41k
      if (alias->alias != NULL
2472
820
        && fn->common.scope == aliases[i]
2473
440
        && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2474
1.41k
      ) {
2475
275
        fn_copy = *fn;
2476
275
        if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2477
46
          fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2478
229
        } else {
2479
229
          fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2480
229
        }
2481
2482
275
        zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2483
2484
275
        zend_string *lcname = zend_string_tolower(alias->alias);
2485
275
        zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2486
275
        zend_string_release_ex(lcname, 0);
2487
275
      }
2488
1.41k
      alias_ptr++;
2489
1.41k
      alias = *alias_ptr;
2490
1.41k
      i++;
2491
1.41k
    }
2492
409
  }
2493
2494
1.86k
  if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2495
    /* is not in hashtable, thus, function is not to be excluded */
2496
1.80k
    memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
2497
2498
    /* apply aliases which have not alias name, just setting visibility */
2499
1.80k
    if (ce->trait_aliases) {
2500
382
      alias_ptr = ce->trait_aliases;
2501
382
      alias = *alias_ptr;
2502
382
      i = 0;
2503
1.70k
      while (alias) {
2504
        /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2505
1.32k
        if (alias->alias == NULL && alias->modifiers != 0
2506
570
          && fn->common.scope == aliases[i]
2507
498
          && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2508
1.32k
        ) {
2509
133
          if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2510
82
            fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2511
82
          } else {
2512
51
            fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2513
51
          }
2514
133
        }
2515
1.32k
        alias_ptr++;
2516
1.32k
        alias = *alias_ptr;
2517
1.32k
        i++;
2518
1.32k
      }
2519
382
    }
2520
2521
1.80k
    zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2522
2523
1.80k
    zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2524
1.80k
  }
2525
1.86k
}
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
387
{
2530
387
  if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2531
10
    zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", ZSTR_VAL(trait->name));
2532
10
  }
2533
2534
575
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2535
554
    if (traits[i] == trait) {
2536
356
      return i;
2537
356
    }
2538
554
  }
2539
21
  zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
2540
377
}
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
1.67k
{
2545
1.67k
  size_t i, j = 0;
2546
1.67k
  zend_trait_precedence *cur_precedence;
2547
1.67k
  zend_trait_method_reference *cur_method_ref;
2548
1.67k
  zend_string *lcname;
2549
1.67k
  HashTable **exclude_tables = NULL;
2550
1.67k
  zend_class_entry **aliases = NULL;
2551
1.67k
  zend_class_entry *trait;
2552
2553
  /* resolve class references */
2554
1.67k
  if (ce->trait_precedences) {
2555
97
    exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2556
97
    i = 0;
2557
97
    zend_trait_precedence **precedences = ce->trait_precedences;
2558
97
    ce->trait_precedences = NULL;
2559
183
    while ((cur_precedence = precedences[i])) {
2560
      /** Resolve classes for all precedence operations. */
2561
116
      cur_method_ref = &cur_precedence->trait_method;
2562
116
      trait = zend_hash_find_ptr_lc(EG(class_table), cur_method_ref->class_name);
2563
116
      if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2564
8
        zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2565
8
      }
2566
108
      zend_check_trait_usage(ce, trait, traits);
2567
2568
      /** Ensure that the preferred method is actually available. */
2569
108
      lcname = zend_string_tolower(cur_method_ref->method_name);
2570
108
      if (!zend_hash_exists(&trait->function_table, lcname)) {
2571
7
        zend_error_noreturn(E_COMPILE_ERROR,
2572
7
               "A precedence rule was defined for %s::%s but this method does not exist",
2573
7
               ZSTR_VAL(trait->name),
2574
7
               ZSTR_VAL(cur_method_ref->method_name));
2575
7
      }
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
181
      for (j = 0; j < cur_precedence->num_excludes; j++) {
2585
95
        zend_string* class_name = cur_precedence->exclude_class_names[j];
2586
95
        zend_class_entry *exclude_ce;
2587
95
        uint32_t trait_num;
2588
2589
95
        exclude_ce = zend_hash_find_ptr_lc(EG(class_table), class_name);
2590
95
        if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2591
3
          zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2592
3
        }
2593
92
        trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2594
92
        if (!exclude_tables[trait_num]) {
2595
76
          ALLOC_HASHTABLE(exclude_tables[trait_num]);
2596
76
          zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2597
76
        }
2598
92
        if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2599
6
          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
6
        }
2601
2602
        /* make sure that the trait method is not from a class mentioned in
2603
         exclude_from_classes, for consistency */
2604
86
        if (trait == exclude_ce) {
2605
6
          zend_error_noreturn(E_COMPILE_ERROR,
2606
6
                 "Inconsistent insteadof definition. "
2607
6
                 "The method %s is to be used from %s, but %s is also on the exclude list",
2608
6
                 ZSTR_VAL(cur_method_ref->method_name),
2609
6
                 ZSTR_VAL(trait->name),
2610
6
                 ZSTR_VAL(trait->name));
2611
6
        }
2612
86
      }
2613
86
      zend_string_release_ex(lcname, 0);
2614
86
      i++;
2615
86
    }
2616
67
    ce->trait_precedences = precedences;
2617
67
  }
2618
2619
1.64k
  if (ce->trait_aliases) {
2620
268
    i = 0;
2621
773
    while (ce->trait_aliases[i]) {
2622
505
      i++;
2623
505
    }
2624
268
    aliases = ecalloc(i, sizeof(zend_class_entry*));
2625
268
    i = 0;
2626
726
    while (ce->trait_aliases[i]) {
2627
497
      const zend_trait_alias *cur_alias = ce->trait_aliases[i];
2628
497
      cur_method_ref = &ce->trait_aliases[i]->trait_method;
2629
497
      lcname = zend_string_tolower(cur_method_ref->method_name);
2630
497
      if (cur_method_ref->class_name) {
2631
        /* For all aliases with an explicit class name, resolve the class now. */
2632
191
        trait = zend_hash_find_ptr_lc(EG(class_table), cur_method_ref->class_name);
2633
191
        if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2634
4
          zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2635
4
        }
2636
187
        zend_check_trait_usage(ce, trait, traits);
2637
187
        aliases[i] = trait;
2638
2639
        /* And, ensure that the referenced method is resolvable, too. */
2640
187
        if (!zend_hash_exists(&trait->function_table, lcname)) {
2641
4
          zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name));
2642
4
        }
2643
306
      } else {
2644
        /* Find out which trait this method refers to. */
2645
306
        trait = NULL;
2646
732
        for (j = 0; j < ce->num_traits; j++) {
2647
434
          if (traits[j]) {
2648
423
            if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2649
291
              if (!trait) {
2650
283
                trait = traits[j];
2651
283
                continue;
2652
283
              }
2653
2654
8
              zend_error_noreturn(E_COMPILE_ERROR,
2655
8
                "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
8
                ZSTR_VAL(cur_method_ref->method_name),
2657
8
                ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2658
8
                ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2659
8
                ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2660
291
            }
2661
423
          }
2662
434
        }
2663
2664
        /* Non-absolute method reference refers to method that does not exist. */
2665
298
        if (!trait) {
2666
23
          if (cur_alias->alias) {
2667
14
            zend_error_noreturn(E_COMPILE_ERROR,
2668
14
              "An alias (%s) was defined for method %s(), but this method does not exist",
2669
14
              ZSTR_VAL(cur_alias->alias),
2670
14
              ZSTR_VAL(cur_alias->trait_method.method_name));
2671
14
          } else {
2672
9
            zend_error_noreturn(E_COMPILE_ERROR,
2673
9
              "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2674
9
              ZSTR_VAL(cur_alias->trait_method.method_name));
2675
9
          }
2676
23
        }
2677
2678
275
        aliases[i] = trait;
2679
275
      }
2680
458
      zend_string_release_ex(lcname, 0);
2681
458
      i++;
2682
458
    }
2683
268
  }
2684
2685
1.60k
  *exclude_tables_ptr = exclude_tables;
2686
1.60k
  *aliases_ptr = aliases;
2687
1.60k
}
2688
/* }}} */
2689
2690
static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases, bool verify_abstract, bool *contains_abstract_methods) /* {{{ */
2691
1.74k
{
2692
1.74k
  uint32_t i;
2693
1.74k
  zend_string *key;
2694
1.74k
  zend_function *fn;
2695
2696
1.74k
  if (exclude_tables) {
2697
150
    for (i = 0; i < ce->num_traits; i++) {
2698
105
      if (traits[i]) {
2699
        /* copies functions, applies defined aliasing, and excludes unused trait methods */
2700
540
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2701
540
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2702
540
          *contains_abstract_methods |= is_abstract;
2703
540
          if (verify_abstract != is_abstract) {
2704
0
            continue;
2705
0
          }
2706
165
          zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2707
165
        } ZEND_HASH_FOREACH_END();
2708
2709
105
        if (exclude_tables[i]) {
2710
57
          zend_hash_destroy(exclude_tables[i]);
2711
57
          FREE_HASHTABLE(exclude_tables[i]);
2712
57
          exclude_tables[i] = NULL;
2713
57
        }
2714
105
      }
2715
105
    }
2716
1.70k
  } else {
2717
3.74k
    for (i = 0; i < ce->num_traits; i++) {
2718
2.04k
      if (traits[i]) {
2719
8.23k
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2720
8.23k
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2721
8.23k
          *contains_abstract_methods |= is_abstract;
2722
8.23k
          if (verify_abstract != is_abstract) {
2723
375
            continue;
2724
375
          }
2725
1.70k
          zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2726
1.70k
        } ZEND_HASH_FOREACH_END();
2727
2.04k
      }
2728
2.04k
    }
2729
1.70k
  }
2730
1.74k
}
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
46
{
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
46
  if (colliding_ce == ce) {
2743
46
    for (size_t i = 0; i < current_trait; i++) {
2744
15
      if (traits[i]
2745
15
        && zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2746
15
        return traits[i];
2747
15
      }
2748
15
    }
2749
46
  }
2750
  /* Traits don't have it, then the composing class (or trait) itself has it. */
2751
31
  return colliding_ce;
2752
46
}
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
46
) {
2759
46
  zend_error_noreturn(E_COMPILE_ERROR,
2760
46
    "%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
46
    ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2762
46
    ZSTR_VAL(trait_constant->ce->name),
2763
46
    ZSTR_VAL(name),
2764
46
    ZSTR_VAL(ce->name)
2765
46
  );
2766
46
}
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
4
) {
2771
4
  zend_error_noreturn(E_COMPILE_ERROR,
2772
4
    "Cannot use trait %s, because %s::%s conflicts with enum case %s::%s",
2773
4
    ZSTR_VAL(trait_constant->ce->name),
2774
4
    ZSTR_VAL(trait_constant->ce->name),
2775
4
    ZSTR_VAL(name),
2776
4
    ZSTR_VAL(ce->name),
2777
4
    ZSTR_VAL(name)
2778
4
  );
2779
4
}
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
247
) {
2784
247
  uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2785
2786
247
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2787
247
  if (zv == NULL) {
2788
    /* No existing constant of the same name, so this one can be added */
2789
133
    return true;
2790
133
  }
2791
2792
114
  zend_class_constant *existing_constant = Z_PTR_P(zv);
2793
2794
114
  if (UNEXPECTED(ZEND_CLASS_CONST_FLAGS(existing_constant) & ZEND_CLASS_CONST_IS_CASE)) {
2795
4
    emit_trait_constant_enum_case_conflict_error(ce, trait_constant, name);
2796
4
    return false;
2797
4
  }
2798
2799
110
  if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2800
15
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2801
15
    return false;
2802
15
  }
2803
2804
95
  if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) {
2805
4
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2806
4
    return false;
2807
91
  } else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2808
42
    inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2809
42
    inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2810
42
    if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
2811
8
      emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2812
8
      return false;
2813
8
    }
2814
42
  }
2815
2816
83
  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
19
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2819
19
    return false;
2820
19
  }
2821
2822
  /* There is an existing constant which is compatible with the new one, so no need to add it */
2823
64
  return false;
2824
83
}
2825
2826
static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2827
1.53k
{
2828
3.36k
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2829
1.82k
    zend_string *constant_name;
2830
1.82k
    zend_class_constant *constant;
2831
2832
1.82k
    if (!traits[i]) {
2833
7
      continue;
2834
7
    }
2835
2836
4.13k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2837
4.13k
      if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2838
133
        zend_class_constant *ct = NULL;
2839
2840
133
        if (ce->type == ZEND_INTERNAL_CLASS) {
2841
0
          ct = malloc(sizeof(zend_class_constant));
2842
133
        } else {
2843
133
          ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2844
133
        }
2845
133
        memcpy(ct, constant, sizeof(zend_class_constant));
2846
133
        constant = ct;
2847
2848
133
        if (Z_TYPE(constant->value) == IS_CONSTANT_AST) {
2849
11
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2850
11
          ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2851
11
        }
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
133
        constant->ce = ce;
2858
2859
133
        Z_TRY_ADDREF(constant->value);
2860
133
        constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2861
133
        if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2862
2
          GC_ADDREF(constant->attributes);
2863
2
        }
2864
2865
133
        zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2866
133
      }
2867
4.13k
    } ZEND_HASH_FOREACH_END();
2868
1.81k
  }
2869
1.53k
}
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
40
{
2874
40
  if (colliding_ce == ce) {
2875
40
    for (size_t i = 0; i < current_trait; i++) {
2876
12
      if (traits[i]
2877
12
       && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2878
12
        return traits[i];
2879
12
      }
2880
12
    }
2881
40
  }
2882
2883
28
  return colliding_ce;
2884
40
}
2885
/* }}} */
2886
2887
static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2888
1.48k
{
2889
1.48k
  zend_property_info *property_info;
2890
1.48k
  const zend_property_info *colliding_prop;
2891
1.48k
  zend_string* prop_name;
2892
1.48k
  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
3.20k
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2900
1.76k
    if (!traits[i]) {
2901
7
      continue;
2902
7
    }
2903
4.53k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2904
4.53k
      uint32_t flags = property_info->flags;
2905
2906
      /* next: check for conflicts with current class */
2907
4.53k
      if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2908
123
        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
123
        } else {
2912
123
          bool is_compatible = false;
2913
123
          uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2914
2915
123
          if (colliding_prop->hooks || property_info->hooks) {
2916
6
            zend_error_noreturn(E_COMPILE_ERROR,
2917
6
              "%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
6
              ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2919
6
              ZSTR_VAL(property_info->ce->name),
2920
6
              ZSTR_VAL(prop_name),
2921
6
              ZSTR_VAL(ce->name));
2922
6
          }
2923
2924
117
          if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2925
104
            verify_property_type_compatibility(property_info, colliding_prop, PROP_INVARIANT, false, false) == INHERITANCE_SUCCESS
2926
117
          ) {
2927
            /* the flags are identical, thus, the properties may be compatible */
2928
96
            zval *op1, *op2;
2929
2930
96
            if (flags & ZEND_ACC_STATIC) {
2931
21
              op1 = &ce->default_static_members_table[colliding_prop->offset];
2932
21
              op2 = &traits[i]->default_static_members_table[property_info->offset];
2933
21
              ZVAL_DEINDIRECT(op1);
2934
21
              ZVAL_DEINDIRECT(op2);
2935
75
            } else {
2936
75
              op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2937
75
              op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2938
75
            }
2939
96
            is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2940
96
          }
2941
2942
117
          if (!is_compatible) {
2943
34
            zend_error_noreturn(E_COMPILE_ERROR,
2944
34
                "%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
34
                ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2946
34
                ZSTR_VAL(property_info->ce->name),
2947
34
                ZSTR_VAL(prop_name),
2948
34
                ZSTR_VAL(ce->name));
2949
34
          }
2950
83
          continue;
2951
117
        }
2952
123
      }
2953
2954
391
      if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS) && !(property_info->flags & ZEND_ACC_READONLY)) {
2955
4
        zend_error_noreturn(E_COMPILE_ERROR,
2956
4
          "Readonly class %s cannot use trait with a non-readonly property %s::$%s",
2957
4
          ZSTR_VAL(ce->name),
2958
4
          ZSTR_VAL(property_info->ce->name),
2959
4
          ZSTR_VAL(prop_name)
2960
4
        );
2961
4
      }
2962
2963
      /* property not found, so lets add it */
2964
387
      zval tmp_prop_value;
2965
387
      if (!(flags & ZEND_ACC_VIRTUAL)) {
2966
362
        if (flags & ZEND_ACC_STATIC) {
2967
106
          prop_value = &traits[i]->default_static_members_table[property_info->offset];
2968
106
          ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2969
256
        } else {
2970
256
          prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2971
256
        }
2972
362
        Z_TRY_ADDREF_P(prop_value);
2973
362
      } else {
2974
25
        prop_value = &tmp_prop_value;
2975
25
        ZVAL_UNDEF(&tmp_prop_value);
2976
25
      }
2977
2978
387
      zend_string *doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2979
2980
387
      zend_type type = property_info->type;
2981
      /* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2982
387
      zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2983
387
      zend_property_info *new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2984
2985
387
      if (property_info->attributes) {
2986
12
        new_prop->attributes = property_info->attributes;
2987
2988
12
        if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2989
1
          GC_ADDREF(new_prop->attributes);
2990
1
        }
2991
12
      }
2992
387
      if (property_info->hooks) {
2993
28
        zend_function **hooks = new_prop->hooks =
2994
28
          zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2995
28
        memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2996
84
        for (uint32_t j = 0; j < ZEND_PROPERTY_HOOK_COUNT; j++) {
2997
56
          if (hooks[j]) {
2998
37
            zend_function *old_fn = hooks[j];
2999
3000
            /* Hooks are not yet supported for internal properties. */
3001
37
            ZEND_ASSERT(ZEND_USER_CODE(old_fn->type));
3002
3003
            /* Copy the function, because we need to adjust the scope. */
3004
37
            zend_function *new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3005
37
            memcpy(new_fn, old_fn, sizeof(zend_op_array));
3006
37
            new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
3007
37
            new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
3008
37
            new_fn->common.prop_info = new_prop;
3009
37
            function_add_ref(new_fn);
3010
3011
37
            zend_fixup_trait_method(new_fn, ce);
3012
3013
37
            hooks[j] = new_fn;
3014
37
          }
3015
56
        }
3016
28
        ce->num_hooked_props++;
3017
28
      }
3018
387
    } ZEND_HASH_FOREACH_END();
3019
1.75k
  }
3020
1.48k
}
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
425
#define MAX_ABSTRACT_INFO_CNT 3
3067
#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
3068
#define DISPLAY_ABSTRACT_FN(idx) \
3069
540
  ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
3070
540
  ai.afn[idx] ? "::" : "", \
3071
540
  ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
3072
540
  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
245
{
3081
245
  if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
3082
232
    ai->afn[ai->cnt] = fn;
3083
232
  }
3084
245
  ai->cnt++;
3085
245
}
3086
/* }}} */
3087
3088
void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
3089
299
{
3090
299
  const zend_function *func;
3091
299
  zend_abstract_info ai;
3092
299
  bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
3093
299
  bool can_be_abstract = (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_ANON_CLASS)) == 0;
3094
299
  memset(&ai, 0, sizeof(ai));
3095
3096
1.44k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
3097
1.44k
    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
174
      if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
3101
150
        zend_verify_abstract_class_function(func, &ai);
3102
150
      }
3103
174
    }
3104
1.44k
  } ZEND_HASH_FOREACH_END();
3105
3106
299
  if (!is_explicit_abstract) {
3107
217
    const zend_property_info *prop_info;
3108
571
    ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
3109
571
      if (prop_info->hooks) {
3110
429
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3111
286
          const zend_function *fn = prop_info->hooks[i];
3112
286
          if (fn && (fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3113
95
            zend_verify_abstract_class_function(fn, &ai);
3114
95
          }
3115
286
        }
3116
143
      }
3117
571
    } ZEND_HASH_FOREACH_END();
3118
217
  }
3119
3120
299
  if (ai.cnt) {
3121
180
    if (!is_explicit_abstract && can_be_abstract) {
3122
160
      zend_error_noreturn(E_ERROR,
3123
160
        "%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
160
        zend_get_object_type_uc(ce),
3125
160
        ZSTR_VAL(ce->name), ai.cnt,
3126
160
        ai.cnt > 1 ? "s" : "",
3127
160
        ai.cnt > 1 ? "s" : "",
3128
160
        DISPLAY_ABSTRACT_FN(0),
3129
160
        DISPLAY_ABSTRACT_FN(1),
3130
160
        DISPLAY_ABSTRACT_FN(2)
3131
160
      );
3132
160
    } else {
3133
20
      zend_error_noreturn(E_ERROR,
3134
20
        "%s %s must implement %d abstract method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3135
20
        zend_get_object_type_uc(ce),
3136
20
        ZSTR_VAL(ce->name), ai.cnt,
3137
20
        ai.cnt > 1 ? "s" : "",
3138
20
        DISPLAY_ABSTRACT_FN(0),
3139
20
        DISPLAY_ABSTRACT_FN(1),
3140
20
        DISPLAY_ABSTRACT_FN(2)
3141
20
      );
3142
20
    }
3143
180
  } else {
3144
    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
3145
119
    ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3146
119
  }
3147
299
}
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
392
static void variance_obligation_dtor(zval *zv) {
3186
392
  efree(Z_PTR_P(zv));
3187
392
}
3188
3189
368
static void variance_obligation_ht_dtor(zval *zv) {
3190
368
  zend_hash_destroy(Z_PTR_P(zv));
3191
368
  FREE_HASHTABLE(Z_PTR_P(zv));
3192
368
}
3193
3194
392
static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
3195
392
  HashTable *ht;
3196
392
  zend_ulong key;
3197
392
  if (!CG(delayed_variance_obligations)) {
3198
306
    ALLOC_HASHTABLE(CG(delayed_variance_obligations));
3199
306
    zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
3200
306
  }
3201
3202
392
  key = (zend_ulong) (uintptr_t) ce;
3203
392
  ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
3204
392
  if (ht) {
3205
24
    return ht;
3206
24
  }
3207
3208
368
  ALLOC_HASHTABLE(ht);
3209
368
  zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
3210
368
  zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
3211
368
  ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
3212
368
  return ht;
3213
392
}
3214
3215
39
static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
3216
39
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3217
39
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3218
39
  obligation->type = OBLIGATION_DEPENDENCY;
3219
39
  obligation->dependency_ce = dependency_ce;
3220
39
  zend_hash_next_index_insert_ptr(obligations, obligation);
3221
39
}
3222
3223
static void add_compatibility_obligation(
3224
    zend_class_entry *ce,
3225
    const zend_function *child_fn, zend_class_entry *child_scope,
3226
284
    const zend_function *parent_fn, zend_class_entry *parent_scope) {
3227
284
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3228
284
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3229
284
  obligation->type = OBLIGATION_COMPATIBILITY;
3230
  /* Copy functions, because they may be stack-allocated in the case of traits. */
3231
284
  if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3232
0
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
3233
284
  } else {
3234
284
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
3235
284
  }
3236
284
  if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3237
17
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
3238
267
  } else {
3239
267
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
3240
267
  }
3241
284
  obligation->child_scope = child_scope;
3242
284
  obligation->parent_scope = parent_scope;
3243
284
  zend_hash_next_index_insert_ptr(obligations, obligation);
3244
284
}
3245
3246
static void add_property_compatibility_obligation(
3247
    zend_class_entry *ce, const zend_property_info *child_prop,
3248
59
    const zend_property_info *parent_prop, prop_variance variance) {
3249
59
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3250
59
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3251
59
  obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
3252
59
  obligation->child_prop = child_prop;
3253
59
  obligation->parent_prop = parent_prop;
3254
59
  obligation->variance = variance;
3255
59
  zend_hash_next_index_insert_ptr(obligations, obligation);
3256
59
}
3257
3258
static void add_class_constant_compatibility_obligation(
3259
    zend_class_entry *ce, const zend_class_constant *child_const,
3260
4
    const zend_class_constant *parent_const, const zend_string *const_name) {
3261
4
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3262
4
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3263
4
  obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY;
3264
4
  obligation->const_name = const_name;
3265
4
  obligation->child_const = child_const;
3266
4
  obligation->parent_const = parent_const;
3267
4
  zend_hash_next_index_insert_ptr(obligations, obligation);
3268
4
}
3269
3270
static void add_property_hook_obligation(
3271
6
    zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func) {
3272
6
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3273
6
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3274
6
  obligation->type = OBLIGATION_PROPERTY_HOOK;
3275
6
  obligation->hooked_prop = hooked_prop;
3276
6
  obligation->hook_func = hook_func;
3277
6
  zend_hash_next_index_insert_ptr(obligations, obligation);
3278
6
}
3279
3280
static void resolve_delayed_variance_obligations(zend_class_entry *ce);
3281
3282
325
static void check_variance_obligation(const variance_obligation *obligation) {
3283
325
  if (obligation->type == OBLIGATION_DEPENDENCY) {
3284
39
    zend_class_entry *dependency_ce = obligation->dependency_ce;
3285
39
    if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3286
34
      zend_class_entry *orig_linking_class = CG(current_linking_class);
3287
3288
34
      CG(current_linking_class) =
3289
34
        (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
3290
34
      resolve_delayed_variance_obligations(dependency_ce);
3291
34
      CG(current_linking_class) = orig_linking_class;
3292
34
    }
3293
286
  } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
3294
226
    inheritance_status status = zend_do_perform_implementation_check(
3295
226
      &obligation->child_fn, obligation->child_scope,
3296
226
      &obligation->parent_fn, obligation->parent_scope);
3297
226
    if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3298
181
      emit_incompatible_method_error(
3299
181
        &obligation->child_fn, obligation->child_scope,
3300
181
        &obligation->parent_fn, obligation->parent_scope, status);
3301
181
    }
3302
    /* Either the compatibility check was successful or only threw a warning. */
3303
226
  } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
3304
50
    verify_property_type_compatibility(obligation->parent_prop, obligation->child_prop, obligation->variance, true, true);
3305
50
  } else if (obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY) {
3306
4
    inheritance_status status =
3307
4
    class_constant_types_compatible(obligation->parent_const, obligation->child_const);
3308
4
    if (status != INHERITANCE_SUCCESS) {
3309
4
      emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name);
3310
4
    }
3311
6
  } else if (obligation->type == OBLIGATION_PROPERTY_HOOK) {
3312
6
    inheritance_status status = zend_verify_property_hook_variance(obligation->hooked_prop, obligation->hook_func);
3313
6
    if (status != INHERITANCE_SUCCESS) {
3314
6
      zend_hooked_property_variance_error(obligation->hooked_prop);
3315
6
    }
3316
6
  } else {
3317
0
    ZEND_UNREACHABLE();
3318
0
  }
3319
325
}
3320
3321
361
static void load_delayed_classes(const zend_class_entry *ce) {
3322
361
  HashTable *delayed_autoloads = CG(delayed_autoloads);
3323
361
  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
361
  HashPosition pos = 0;
3333
361
  zend_string *name;
3334
361
  zend_ulong idx;
3335
853
  while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
3336
853
      != HASH_KEY_NON_EXISTENT) {
3337
507
    zend_string_addref(name);
3338
507
    zend_hash_del(delayed_autoloads, name);
3339
507
    zend_lookup_class(name);
3340
507
    zend_string_release(name);
3341
507
    if (EG(exception)) {
3342
15
      zend_exception_uncaught_error(
3343
15
        "During inheritance of %s, while autoloading %s",
3344
15
        ZSTR_VAL(ce->name), ZSTR_VAL(name));
3345
15
    }
3346
507
  }
3347
361
}
3348
3349
315
static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
3350
315
  HashTable *all_obligations = CG(delayed_variance_obligations);
3351
315
  zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
3352
3353
315
  ZEND_ASSERT(all_obligations != NULL);
3354
315
  const HashTable *obligations = zend_hash_index_find_ptr(all_obligations, num_key);
3355
315
  ZEND_ASSERT(obligations != NULL);
3356
3357
315
  variance_obligation *obligation;
3358
965
  ZEND_HASH_FOREACH_PTR(obligations, obligation) {
3359
965
    check_variance_obligation(obligation);
3360
965
  } ZEND_HASH_FOREACH_END();
3361
3362
315
  zend_inheritance_check_override(ce);
3363
3364
315
  ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
3365
315
  ce->ce_flags |= ZEND_ACC_LINKED;
3366
315
  zend_hash_index_del(all_obligations, num_key);
3367
315
}
3368
3369
321
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
321
  if (CG(unlinked_uses)
3375
10
      && zend_hash_index_del(CG(unlinked_uses), (zend_ulong)(uintptr_t)ce) == SUCCESS) {
3376
10
    zend_exception_uncaught_error(
3377
10
      "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
3378
10
  }
3379
321
}
3380
3381
62.8k
#define zend_update_inherited_handler(handler) do { \
3382
62.8k
    if (ce->handler == (zend_function*)op_array) { \
3383
1.28k
      ce->handler = (zend_function*)new_op_array; \
3384
1.28k
    } \
3385
62.8k
  } while (0)
3386
3387
static zend_op_array *zend_lazy_method_load(
3388
4.94k
    const zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3389
4.94k
  ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3390
4.94k
  ZEND_ASSERT(op_array->scope == pce);
3391
4.94k
  ZEND_ASSERT(op_array->prototype == NULL);
3392
4.94k
  zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3393
4.94k
  memcpy(new_op_array, op_array, sizeof(zend_op_array));
3394
4.94k
  new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3395
4.94k
  new_op_array->scope = ce;
3396
4.94k
  ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3397
4.94k
  ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3398
3399
4.94k
  return new_op_array;
3400
4.94k
}
3401
3402
static zend_class_entry *zend_lazy_class_load(const zend_class_entry *pce)
3403
5.66k
{
3404
5.66k
  zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3405
3406
5.66k
  memcpy(ce, pce, sizeof(zend_class_entry));
3407
5.66k
  ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3408
5.66k
  ce->refcount = 1;
3409
5.66k
  ce->inheritance_cache = NULL;
3410
5.66k
  if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3411
0
    ZEND_MAP_PTR_NEW(ce->mutable_data);
3412
5.66k
  } else {
3413
5.66k
    ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3414
5.66k
  }
3415
3416
  /* properties */
3417
5.66k
  if (ce->default_properties_table) {
3418
1.99k
    zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3419
1.99k
    zval *src = ce->default_properties_table;
3420
1.99k
    const zval *end = src + ce->default_properties_count;
3421
3422
1.99k
    ce->default_properties_table = dst;
3423
4.64k
    for (; src != end; src++, dst++) {
3424
2.65k
      ZVAL_COPY_VALUE_PROP(dst, src);
3425
2.65k
    }
3426
1.99k
  }
3427
3428
  /* methods */
3429
5.66k
  ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3430
5.66k
  if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3431
2.44k
    Bucket *p = emalloc(HT_SIZE(&ce->function_table));
3432
2.44k
    memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3433
2.44k
    HT_SET_DATA_ADDR(&ce->function_table, p);
3434
2.44k
    p = ce->function_table.arData;
3435
2.44k
    const Bucket *end = p + ce->function_table.nNumUsed;
3436
7.27k
    for (; p != end; p++) {
3437
4.83k
      zend_op_array *op_array = Z_PTR(p->val);
3438
4.83k
      zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3439
3440
4.83k
      zend_update_inherited_handler(constructor);
3441
4.83k
      zend_update_inherited_handler(destructor);
3442
4.83k
      zend_update_inherited_handler(clone);
3443
4.83k
      zend_update_inherited_handler(__get);
3444
4.83k
      zend_update_inherited_handler(__set);
3445
4.83k
      zend_update_inherited_handler(__call);
3446
4.83k
      zend_update_inherited_handler(__isset);
3447
4.83k
      zend_update_inherited_handler(__unset);
3448
4.83k
      zend_update_inherited_handler(__tostring);
3449
4.83k
      zend_update_inherited_handler(__callstatic);
3450
4.83k
      zend_update_inherited_handler(__debugInfo);
3451
4.83k
      zend_update_inherited_handler(__serialize);
3452
4.83k
      zend_update_inherited_handler(__unserialize);
3453
4.83k
    }
3454
2.44k
  }
3455
3456
  /* static members */
3457
5.66k
  if (ce->default_static_members_table) {
3458
74
    zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
3459
74
    zval *src = ce->default_static_members_table;
3460
74
    const zval *end = src + ce->default_static_members_count;
3461
3462
74
    ce->default_static_members_table = dst;
3463
160
    for (; src != end; src++, dst++) {
3464
86
      ZVAL_COPY_VALUE(dst, src);
3465
86
    }
3466
74
  }
3467
5.66k
  ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3468
3469
  /* properties_info */
3470
5.66k
  if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3471
2.09k
    Bucket *p = emalloc(HT_SIZE(&ce->properties_info));
3472
2.09k
    memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3473
2.09k
    HT_SET_DATA_ADDR(&ce->properties_info, p);
3474
2.09k
    p = ce->properties_info.arData;
3475
2.09k
    const Bucket *end = p + ce->properties_info.nNumUsed;
3476
4.92k
    for (; p != end; p++) {
3477
2.82k
      zend_property_info *new_prop_info;
3478
3479
2.82k
      const zend_property_info *prop_info = Z_PTR(p->val);
3480
2.82k
      ZEND_ASSERT(prop_info->ce == pce);
3481
2.82k
      ZEND_ASSERT(prop_info->prototype == prop_info);
3482
2.82k
      new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3483
2.82k
      Z_PTR(p->val) = new_prop_info;
3484
2.82k
      memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3485
2.82k
      new_prop_info->ce = ce;
3486
2.82k
      new_prop_info->prototype = new_prop_info;
3487
      /* Deep copy the type information */
3488
2.82k
      zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3489
2.82k
      if (new_prop_info->hooks) {
3490
95
        new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3491
95
        memcpy(new_prop_info->hooks, prop_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3492
285
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3493
190
          if (new_prop_info->hooks[i]) {
3494
104
            zend_op_array *hook = zend_lazy_method_load((zend_op_array *) new_prop_info->hooks[i], ce, pce);
3495
104
            ZEND_ASSERT(hook->prop_info == prop_info);
3496
104
            hook->prop_info = new_prop_info;
3497
104
            new_prop_info->ce = ce;
3498
104
            new_prop_info->hooks[i] = (zend_function *) hook;
3499
104
          }
3500
190
        }
3501
95
      }
3502
2.82k
    }
3503
2.09k
  }
3504
3505
  /* constants table */
3506
5.66k
  if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3507
1.34k
    Bucket *p = emalloc(HT_SIZE(&ce->constants_table));
3508
1.34k
    memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3509
1.34k
    HT_SET_DATA_ADDR(&ce->constants_table, p);
3510
1.34k
    p = ce->constants_table.arData;
3511
1.34k
    const Bucket *end = p + ce->constants_table.nNumUsed;
3512
3.82k
    for (; p != end; p++) {
3513
2.48k
      zend_class_constant *new_c;
3514
3515
2.48k
      const zend_class_constant *c = Z_PTR(p->val);
3516
2.48k
      ZEND_ASSERT(c->ce == pce);
3517
2.48k
      new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3518
2.48k
      Z_PTR(p->val) = new_c;
3519
2.48k
      memcpy(new_c, c, sizeof(zend_class_constant));
3520
2.48k
      new_c->ce = ce;
3521
2.48k
    }
3522
1.34k
  }
3523
3524
5.66k
  return ce;
3525
5.66k
}
3526
3527
#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
3528
18.5k
# define UPDATE_IS_CACHEABLE(ce) do { \
3529
18.5k
      if ((ce)->type == ZEND_USER_CLASS) { \
3530
13.5k
        is_cacheable &= (ce)->ce_flags; \
3531
13.5k
      } \
3532
18.5k
    } 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
7.78k
{
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
7.78k
  zend_class_entry *parent = NULL;
3546
7.78k
  zend_class_entry **traits_and_interfaces = NULL;
3547
7.78k
  zend_class_entry *proto = NULL;
3548
7.78k
  zend_class_entry *orig_linking_class;
3549
7.78k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3550
7.78k
  uint32_t i, j;
3551
7.78k
  zval *zv;
3552
7.78k
  ALLOCA_FLAG(use_heap)
3553
3554
7.78k
  SET_ALLOCA_FLAG(use_heap);
3555
7.78k
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3556
3557
7.78k
  if (ce->parent_name) {
3558
1.83k
    parent = zend_fetch_class_by_name(
3559
1.83k
      ce->parent_name, lc_parent_name,
3560
1.83k
      ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3561
1.83k
    if (!parent) {
3562
230
      check_unrecoverable_load_failure(ce);
3563
230
      return NULL;
3564
230
    }
3565
1.60k
    UPDATE_IS_CACHEABLE(parent);
3566
1.60k
  }
3567
3568
7.55k
  if (ce->num_traits || ce->num_interfaces) {
3569
6.57k
    traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3570
3571
9.00k
    for (i = 0; i < ce->num_traits; i++) {
3572
2.50k
      zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3573
2.50k
        ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
3574
2.50k
      if (UNEXPECTED(trait == NULL)) {
3575
49
        free_alloca(traits_and_interfaces, use_heap);
3576
49
        return NULL;
3577
49
      }
3578
2.45k
      if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
3579
16
        zend_throw_error(NULL, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
3580
16
        free_alloca(traits_and_interfaces, use_heap);
3581
16
        return NULL;
3582
16
      }
3583
2.43k
      if (UNEXPECTED(trait->ce_flags & ZEND_ACC_DEPRECATED)) {
3584
85
        zend_use_of_deprecated_trait(trait, ce->name);
3585
85
        if (UNEXPECTED(EG(exception))) {
3586
6
          free_alloca(traits_and_interfaces, use_heap);
3587
6
          return NULL;
3588
6
        }
3589
85
      }
3590
2.95k
      for (j = 0; j < i; j++) {
3591
552
        if (traits_and_interfaces[j] == trait) {
3592
          /* skip duplications */
3593
27
          trait = NULL;
3594
27
          break;
3595
27
        }
3596
552
      }
3597
2.42k
      traits_and_interfaces[i] = trait;
3598
2.42k
      if (trait) {
3599
2.40k
        UPDATE_IS_CACHEABLE(trait);
3600
2.40k
      }
3601
2.42k
    }
3602
6.57k
  }
3603
3604
7.48k
  if (ce->num_interfaces) {
3605
10.3k
    for (i = 0; i < ce->num_interfaces; i++) {
3606
5.78k
      zend_class_entry *iface = zend_fetch_class_by_name(
3607
5.78k
        ce->interface_names[i].name, ce->interface_names[i].lc_name,
3608
5.78k
        ZEND_FETCH_CLASS_INTERFACE |
3609
5.78k
        ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3610
5.78k
      if (!iface) {
3611
91
        check_unrecoverable_load_failure(ce);
3612
91
        free_alloca(traits_and_interfaces, use_heap);
3613
91
        return NULL;
3614
91
      }
3615
5.68k
      traits_and_interfaces[ce->num_traits + i] = iface;
3616
5.68k
      if (iface) {
3617
5.68k
        UPDATE_IS_CACHEABLE(iface);
3618
5.68k
      }
3619
5.68k
    }
3620
4.68k
  }
3621
3622
7.38k
#ifndef ZEND_WIN32
3623
7.38k
  if (ce->ce_flags & ZEND_ACC_ENUM) {
3624
    /* We will add internal methods. */
3625
1.59k
    is_cacheable = false;
3626
1.59k
  }
3627
7.38k
#endif
3628
3629
7.38k
  if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3630
5.07k
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3631
5.07k
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3632
5.07k
      if (ret) {
3633
859
        if (traits_and_interfaces) {
3634
780
          free_alloca(traits_and_interfaces, use_heap);
3635
780
        }
3636
859
        zv = zend_hash_find_known_hash(CG(class_table), key);
3637
859
        Z_CE_P(zv) = ret;
3638
859
        return ret;
3639
859
      }
3640
5.07k
    } else {
3641
0
      is_cacheable = 0;
3642
0
    }
3643
4.21k
    proto = ce;
3644
4.21k
  }
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
7.38k
  bool orig_record_errors = EG(record_errors);
3651
6.53k
  if (!orig_record_errors) {
3652
6.49k
    zend_begin_record_errors();
3653
6.49k
  }
3654
3655
6.53k
  zend_try {
3656
6.49k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3657
      /* Lazy class loading */
3658
5.63k
      ce = zend_lazy_class_load(ce);
3659
5.63k
      zv = zend_hash_find_known_hash(CG(class_table), key);
3660
5.63k
      Z_CE_P(zv) = ce;
3661
5.63k
    } 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
6.49k
    if (CG(unlinked_uses)) {
3670
62
      zend_hash_index_del(CG(unlinked_uses), (zend_ulong)(uintptr_t) ce);
3671
62
    }
3672
3673
6.49k
    orig_linking_class = CG(current_linking_class);
3674
6.49k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3675
3676
6.49k
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3677
      /* Only register builtin enum methods during inheritance to avoid persisting them in
3678
       * opcache. */
3679
1.59k
      zend_enum_register_funcs(ce);
3680
1.59k
    }
3681
3682
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3683
    zend_link_hooked_object_iter(ce);
3684
#endif
3685
3686
6.49k
    HashTable **trait_exclude_tables;
3687
6.49k
    zend_class_entry **trait_aliases;
3688
6.49k
    bool trait_contains_abstract_methods = false;
3689
6.49k
    if (ce->num_traits) {
3690
1.67k
      zend_traits_init_trait_structures(ce, traits_and_interfaces, &trait_exclude_tables, &trait_aliases);
3691
1.67k
      zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods);
3692
1.67k
      zend_do_traits_constant_binding(ce, traits_and_interfaces);
3693
1.67k
      zend_do_traits_property_binding(ce, traits_and_interfaces);
3694
3695
1.67k
      zend_function *fn;
3696
7.18k
      ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3697
7.18k
        zend_fixup_trait_method(fn, ce);
3698
7.18k
      } ZEND_HASH_FOREACH_END();
3699
1.67k
    }
3700
6.49k
    if (parent) {
3701
1.34k
      if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3702
39
        add_dependency_obligation(ce, parent);
3703
39
      }
3704
1.34k
      zend_do_inheritance(ce, parent);
3705
1.34k
    }
3706
6.26k
    if (ce->num_traits) {
3707
1.42k
      if (trait_contains_abstract_methods) {
3708
175
        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
175
        zend_function *fn;
3713
877
        ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3714
877
          zend_fixup_trait_method(fn, ce);
3715
877
        } ZEND_HASH_FOREACH_END();
3716
175
      }
3717
3718
1.42k
      if (trait_exclude_tables) {
3719
138
        for (i = 0; i < ce->num_traits; i++) {
3720
96
          if (traits_and_interfaces[i]) {
3721
96
            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
96
          }
3726
96
        }
3727
42
        efree(trait_exclude_tables);
3728
42
      }
3729
1.39k
      if (trait_aliases) {
3730
199
        efree(trait_aliases);
3731
199
      }
3732
1.39k
    }
3733
6.26k
    if (ce->num_interfaces) {
3734
      /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3735
4.06k
      uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3736
4.06k
      zend_class_entry **interfaces = emalloc(
3737
4.06k
          sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3738
3739
4.06k
      if (num_parent_interfaces) {
3740
76
        memcpy(interfaces, parent->interfaces,
3741
76
             sizeof(zend_class_entry *) * num_parent_interfaces);
3742
76
      }
3743
4.06k
      memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3744
4.06k
           sizeof(zend_class_entry *) * ce->num_interfaces);
3745
3746
4.06k
      zend_do_implement_interfaces(ce, interfaces);
3747
4.06k
    } else if (parent && parent->num_interfaces) {
3748
123
      zend_do_inherit_interfaces(ce, parent);
3749
123
    }
3750
6.24k
    if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3751
5.63k
      && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3752
6.24k
        ) {
3753
186
      zend_verify_abstract_class(ce);
3754
186
    }
3755
6.24k
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3756
1.54k
      zend_verify_enum(ce);
3757
1.54k
    }
3758
6.24k
    if (ce->num_hooked_prop_variance_checks) {
3759
18
      const zend_property_info *prop_info;
3760
72
      ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
3761
72
        if (prop_info->ce == ce && prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
3762
18
          switch (zend_verify_property_hook_variance(prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
3763
8
            case INHERITANCE_SUCCESS:
3764
8
              break;
3765
4
            case INHERITANCE_ERROR:
3766
4
              zend_hooked_property_variance_error(prop_info);
3767
0
              break;
3768
6
            case INHERITANCE_UNRESOLVED:
3769
6
              add_property_hook_obligation(ce, prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET]);
3770
6
              break;
3771
0
            case INHERITANCE_WARNING:
3772
0
              ZEND_UNREACHABLE();
3773
18
          }
3774
18
        }
3775
72
      } ZEND_HASH_FOREACH_END();
3776
18
    }
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
6.23k
    if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3781
641
      && !zend_class_implements_interface(ce, zend_ce_stringable)) {
3782
22
      ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
3783
22
      ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
3784
22
      ce->num_interfaces++;
3785
22
      ce->interfaces = perealloc(ce->interfaces,
3786
22
                     sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
3787
22
      ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
3788
22
      do_interface_implementation(ce, zend_ce_stringable);
3789
22
    }
3790
3791
6.23k
    zend_build_properties_info_table(ce);
3792
6.23k
  } zend_catch {
3793
    /* Do not leak recorded errors to the next linked class. */
3794
768
    if (!orig_record_errors) {
3795
768
      EG(record_errors) = false;
3796
768
      zend_free_recorded_errors();
3797
768
    }
3798
768
    zend_bailout();
3799
5.72k
  } zend_end_try();
3800
3801
5.72k
  EG(record_errors) = orig_record_errors;
3802
3803
5.72k
  if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3804
5.36k
    zend_inheritance_check_override(ce);
3805
5.36k
    ce->ce_flags |= ZEND_ACC_LINKED;
3806
5.36k
  } else {
3807
361
    ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
3808
361
    if (CG(current_linking_class)) {
3809
267
      ce->ce_flags |= ZEND_ACC_CACHEABLE;
3810
267
    }
3811
361
    load_delayed_classes(ce);
3812
361
    if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3813
281
      resolve_delayed_variance_obligations(ce);
3814
281
    }
3815
    /* Delayed variance resolution can re-enter linking before the full
3816
     * hierarchy is linked. See ext/opcache/tests/gh20469*.phpt. */
3817
361
    if (CG(unlinked_uses) && zend_hash_index_exists(CG(unlinked_uses), (zend_long)(uintptr_t) ce)) {
3818
35
      ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3819
35
    }
3820
361
    if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3821
8
      ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3822
353
    } else {
3823
353
      CG(current_linking_class) = NULL;
3824
353
    }
3825
361
  }
3826
3827
5.72k
  bool was_cacheable = is_cacheable;
3828
5.72k
  if (!CG(current_linking_class)) {
3829
1.98k
    is_cacheable = 0;
3830
1.98k
  }
3831
5.72k
  CG(current_linking_class) = orig_linking_class;
3832
3833
5.72k
  if (is_cacheable) {
3834
3.38k
    HashTable *ht = (HashTable*)ce->inheritance_cache;
3835
3.38k
    zend_class_entry *new_ce;
3836
3837
3.38k
    ce->inheritance_cache = NULL;
3838
3.38k
    new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3839
3.38k
    if (new_ce) {
3840
3.38k
      zv = zend_hash_find_known_hash(CG(class_table), key);
3841
3.38k
      ce = new_ce;
3842
3.38k
      Z_CE_P(zv) = ce;
3843
3.38k
    }
3844
3.38k
    if (ht) {
3845
108
      zend_hash_destroy(ht);
3846
108
      FREE_HASHTABLE(ht);
3847
108
    }
3848
3.38k
  } 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
5.72k
  if (!orig_record_errors) {
3858
5.37k
    zend_emit_recorded_errors();
3859
5.37k
    zend_free_recorded_errors();
3860
5.37k
  }
3861
5.72k
  if (traits_and_interfaces) {
3862
4.86k
    free_alloca(traits_and_interfaces, use_heap);
3863
4.86k
  }
3864
3865
5.72k
  if (ZSTR_HAS_CE_CACHE(ce->name)) {
3866
4.65k
    ZSTR_SET_CE_CACHE(ce->name, ce);
3867
4.65k
  }
3868
3869
5.72k
  return ce;
3870
5.72k
}
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
8.86k
{
3876
8.86k
  zend_string *key;
3877
8.86k
  zend_function *parent_func;
3878
8.86k
  const zend_property_info *parent_info;
3879
8.86k
  const zend_class_constant *parent_const;
3880
8.86k
  inheritance_status overall_status = INHERITANCE_SUCCESS;
3881
3882
65.8k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3883
65.8k
    zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3884
65.8k
    if (zv) {
3885
3.51k
      zend_function *child_func = Z_FUNC_P(zv);
3886
3.51k
      inheritance_status status =
3887
3.51k
        do_inheritance_check_on_method(
3888
3.51k
          child_func, child_func->common.scope,
3889
3.51k
          parent_func, parent_func->common.scope,
3890
3.51k
          ce, NULL,
3891
3.51k
          ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3892
3.51k
      if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3893
311
        overall_status = INHERITANCE_WARNING;
3894
3.20k
      } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3895
1.19k
        return status;
3896
1.19k
      }
3897
3.51k
    }
3898
65.8k
  } ZEND_HASH_FOREACH_END();
3899
3900
33.6k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3901
33.6k
    const zval *zv;
3902
33.6k
    if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3903
5.12k
      continue;
3904
5.12k
    }
3905
3906
4.05k
    zv = zend_hash_find_known_hash(&ce->properties_info, key);
3907
4.05k
    if (zv) {
3908
2.23k
      const zend_property_info *child_info = Z_PTR_P(zv);
3909
2.23k
      if (ZEND_TYPE_IS_SET(child_info->type)) {
3910
2.13k
        inheritance_status status = verify_property_type_compatibility(parent_info, child_info, prop_get_variance(parent_info), false, false);
3911
2.13k
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3912
887
          return status;
3913
887
        }
3914
2.13k
      }
3915
2.23k
    }
3916
4.05k
  } ZEND_HASH_FOREACH_END();
3917
3918
24.1k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3919
24.1k
    const zval *zv;
3920
24.1k
    if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3921
808
      continue;
3922
808
    }
3923
3924
4.47k
    zv = zend_hash_find_known_hash(&ce->constants_table, key);
3925
4.47k
    if (zv) {
3926
246
      const zend_class_constant *child_const = Z_PTR_P(zv);
3927
246
      if (ZEND_TYPE_IS_SET(child_const->type)) {
3928
215
        inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3929
215
        ZEND_ASSERT(status != INHERITANCE_WARNING);
3930
215
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3931
104
          return status;
3932
104
        }
3933
215
      }
3934
246
    }
3935
4.47k
  } ZEND_HASH_FOREACH_END();
3936
3937
6.67k
  return overall_status;
3938
6.78k
}
3939
/* }}} */
3940
3941
7.85k
static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3942
7.85k
  if (delayed_early_binding) {
3943
33
    if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3944
33
      if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3945
33
        Z_CE_P(delayed_early_binding) = ce;
3946
33
        return true;
3947
33
      }
3948
33
    } 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
7.82k
  if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3960
6.11k
    return true;
3961
6.11k
  }
3962
1.70k
  return false;
3963
7.82k
}
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
8.87k
{
3967
8.87k
  inheritance_status status;
3968
8.87k
  zend_class_entry *proto = NULL;
3969
8.87k
  zend_class_entry *orig_linking_class;
3970
3971
8.87k
  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
8.87k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3981
8.87k
  UPDATE_IS_CACHEABLE(parent_ce);
3982
8.87k
  if (is_cacheable) {
3983
259
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3984
259
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3985
259
      if (ret) {
3986
7
        if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
3987
0
          return NULL;
3988
0
        }
3989
7
        zend_observer_class_linked_notify(ret, lcname);
3990
7
        return ret;
3991
7
      }
3992
259
    } else {
3993
0
      is_cacheable = 0;
3994
0
    }
3995
252
    proto = ce;
3996
252
  }
3997
3998
8.86k
  orig_linking_class = CG(current_linking_class);
3999
8.86k
  CG(current_linking_class) = NULL;
4000
8.86k
  status = zend_can_early_bind(ce, parent_ce);
4001
8.86k
  CG(current_linking_class) = orig_linking_class;
4002
8.86k
  if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
4003
7.84k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
4004
      /* Lazy class loading */
4005
26
      ce = zend_lazy_class_load(ce);
4006
7.82k
    } 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
7.84k
    if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
4013
1.70k
      return NULL;
4014
1.70k
    }
4015
4016
6.14k
    orig_linking_class = CG(current_linking_class);
4017
6.14k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
4018
4019
6.14k
    bool orig_record_errors = EG(record_errors);
4020
4021
6.14k
    zend_try{
4022
6.14k
      CG(zend_lineno) = ce->info.user.line_start;
4023
4024
6.14k
      if (!orig_record_errors) {
4025
76
        zend_begin_record_errors();
4026
76
      }
4027
4028
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
4029
      zend_link_hooked_object_iter(ce);
4030
#endif
4031
4032
6.14k
      zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
4033
6.14k
      if (parent_ce && parent_ce->num_interfaces) {
4034
584
        zend_do_inherit_interfaces(ce, parent_ce);
4035
584
      }
4036
6.14k
      zend_build_properties_info_table(ce);
4037
6.14k
      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
44
        zend_verify_abstract_class(ce);
4039
44
      }
4040
6.14k
      zend_inheritance_check_override(ce);
4041
6.14k
      ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
4042
6.14k
      ce->ce_flags |= ZEND_ACC_LINKED;
4043
4044
5.25k
      CG(current_linking_class) = orig_linking_class;
4045
5.25k
    } zend_catch {
4046
886
      if (!orig_record_errors) {
4047
7
        EG(record_errors) = false;
4048
7
        zend_free_recorded_errors();
4049
7
      }
4050
886
      zend_bailout();
4051
5.25k
    } zend_end_try();
4052
4053
5.25k
    if (is_cacheable) {
4054
23
      HashTable *ht = (HashTable*)ce->inheritance_cache;
4055
23
      zend_class_entry *new_ce;
4056
4057
23
      ce->inheritance_cache = NULL;
4058
23
      new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
4059
23
      if (new_ce) {
4060
23
        zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
4061
23
        ce = new_ce;
4062
23
        Z_CE_P(zv) = ce;
4063
23
      }
4064
23
      if (ht) {
4065
0
        zend_hash_destroy(ht);
4066
0
        FREE_HASHTABLE(ht);
4067
0
      }
4068
23
    }
4069
4070
5.25k
    if (!orig_record_errors) {
4071
69
      zend_emit_recorded_errors();
4072
69
      zend_free_recorded_errors();
4073
69
    }
4074
4075
5.25k
    if (ZSTR_HAS_CE_CACHE(ce->name)) {
4076
3.14k
      ZSTR_SET_CE_CACHE(ce->name, ce);
4077
3.14k
    }
4078
5.25k
    zend_observer_class_linked_notify(ce, lcname);
4079
4080
5.25k
    return ce;
4081
5.25k
  }
4082
1.01k
  return NULL;
4083
8.86k
}
4084
/* }}} */