Coverage Report

Created: 2026-01-18 06:49

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