Coverage Report

Created: 2026-07-25 06:39

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