Coverage Report

Created: 2026-01-18 06:47

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
0
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
92
0
  if (ZEND_TYPE_HAS_LIST(*type)) {
93
0
    zend_type_list_copy_ctor(type, use_arena, persistent);
94
0
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
95
0
    zend_string_addref(ZEND_TYPE_NAME(*type));
96
0
  }
97
0
}
98
99
static zend_function *zend_duplicate_internal_function(const zend_function *func, const zend_class_entry *ce) /* {{{ */
100
19.3k
{
101
19.3k
  zend_function *new_function;
102
103
19.3k
  if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
104
2.32k
    new_function = (zend_function *)pemalloc(sizeof(zend_internal_function), 1);
105
2.32k
    memcpy(new_function, func, sizeof(zend_internal_function));
106
16.9k
  } else {
107
16.9k
    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
108
16.9k
    memcpy(new_function, func, sizeof(zend_internal_function));
109
16.9k
    new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
110
16.9k
  }
111
19.3k
  if (EXPECTED(new_function->common.function_name)) {
112
19.3k
    zend_string_addref(new_function->common.function_name);
113
19.3k
  }
114
19.3k
  return new_function;
115
19.3k
}
116
/* }}} */
117
118
static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
119
20.5k
{
120
20.5k
  if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
121
19.3k
    return zend_duplicate_internal_function(func, ce);
122
19.3k
  } else {
123
1.27k
    if (func->op_array.refcount) {
124
1.27k
      (*func->op_array.refcount)++;
125
1.27k
    }
126
1.27k
    if (EXPECTED(func->op_array.function_name)) {
127
1.27k
      zend_string_addref(func->op_array.function_name);
128
1.27k
    }
129
1.27k
    return func;
130
1.27k
  }
131
20.5k
}
132
/* }}} */
133
134
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
135
2.72k
{
136
2.72k
  zend_class_entry *parent = ce->parent;
137
138
2.72k
  ZEND_ASSERT(parent != NULL);
139
140
  /* You cannot change create_object */
141
2.72k
  ce->create_object = parent->create_object;
142
143
  /* Inherit special functions if needed */
144
2.72k
  if (EXPECTED(!ce->get_iterator)) {
145
2.42k
    ce->get_iterator = parent->get_iterator;
146
2.42k
  }
147
2.72k
  if (EXPECTED(!ce->__get)) {
148
2.67k
    ce->__get = parent->__get;
149
2.67k
  }
150
2.72k
  if (EXPECTED(!ce->__set)) {
151
2.71k
    ce->__set = parent->__set;
152
2.71k
  }
153
2.72k
  if (EXPECTED(!ce->__unset)) {
154
2.69k
    ce->__unset = parent->__unset;
155
2.69k
  }
156
2.72k
  if (EXPECTED(!ce->__isset)) {
157
2.72k
    ce->__isset = parent->__isset;
158
2.72k
  }
159
2.72k
  if (EXPECTED(!ce->__call)) {
160
2.68k
    ce->__call = parent->__call;
161
2.68k
  }
162
2.72k
  if (EXPECTED(!ce->__callstatic)) {
163
2.68k
    ce->__callstatic = parent->__callstatic;
164
2.68k
  }
165
2.72k
  if (EXPECTED(!ce->__tostring)) {
166
2.71k
    ce->__tostring = parent->__tostring;
167
2.71k
  }
168
2.72k
  if (EXPECTED(!ce->clone)) {
169
2.71k
    ce->clone = parent->clone;
170
2.71k
  }
171
2.72k
  if (EXPECTED(!ce->__serialize)) {
172
2.72k
    ce->__serialize = parent->__serialize;
173
2.72k
  }
174
2.72k
  if (EXPECTED(!ce->__unserialize)) {
175
2.70k
    ce->__unserialize = parent->__unserialize;
176
2.70k
  }
177
2.72k
  if (EXPECTED(!ce->serialize)) {
178
2.72k
    ce->serialize = parent->serialize;
179
2.72k
  }
180
2.72k
  if (EXPECTED(!ce->unserialize)) {
181
2.72k
    ce->unserialize = parent->unserialize;
182
2.72k
  }
183
2.72k
  if (!ce->destructor) {
184
2.72k
    ce->destructor = parent->destructor;
185
2.72k
  }
186
2.72k
  if (EXPECTED(!ce->__debugInfo)) {
187
2.69k
    ce->__debugInfo = parent->__debugInfo;
188
2.69k
  }
189
190
2.72k
  if (ce->constructor) {
191
127
    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
127
    return;
197
127
  }
198
199
2.60k
  ce->constructor = parent->constructor;
200
2.60k
}
201
/* }}} */
202
203
const char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
204
5
{
205
5
  if (fn_flags & ZEND_ACC_PUBLIC) {
206
3
    return "public";
207
3
  } else if (fn_flags & ZEND_ACC_PRIVATE) {
208
0
    return "private";
209
2
  } else {
210
2
    ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
211
2
    return "protected";
212
2
  }
213
5
}
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.02k
    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
44
    zend_string *lc_name = zend_string_tolower(name);
269
270
44
    ce = zend_hash_find_ptr(CG(class_table), lc_name);
271
272
44
    zend_string_release(lc_name);
273
274
44
    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
44
    return ce;
281
44
  }
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.40k
static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) {
314
2.40k
  if (ce1 == ce2) {
315
219
    return true;
316
219
  }
317
318
2.18k
  if (ce1->ce_flags & ZEND_ACC_LINKED) {
319
1.93k
    return instanceof_function(ce1, ce2);
320
1.93k
  }
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.28k
{
388
1.28k
  HashTable *ht;
389
390
1.28k
  ZEND_ASSERT(class_name);
391
1.28k
  if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
392
1.28k
    return;
393
1.28k
  } 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.5k
    zend_class_entry *proto_scope, const zend_type proto_type) {
477
15.5k
  zend_class_entry *fe_ce = NULL;
478
15.5k
  bool have_unresolved = false;
479
480
  /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
481
15.5k
  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.3k
  if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_CALLABLE) {
496
392
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
497
392
    if (!fe_ce) {
498
193
      have_unresolved = true;
499
199
    } else if (fe_ce == zend_ce_closure) {
500
158
      track_class_dependency(fe_ce, fe_class_name);
501
158
      return INHERITANCE_SUCCESS;
502
158
    }
503
392
  }
504
505
  /* If the parent has 'static' as a return type, then final classes could replace it with self */
506
15.1k
  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.1k
  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.1k
  bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
521
58.4k
  ZEND_TYPE_FOREACH(proto_type, single_type) {
522
58.4k
    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
34.8k
    zend_class_entry *proto_ce;
545
34.8k
    zend_string *proto_class_name = NULL;
546
34.8k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
547
34.0k
      proto_class_name =
548
34.0k
        resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
549
34.0k
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
550
2.80k
        if (!is_intersection) {
551
2.47k
          return INHERITANCE_SUCCESS;
552
2.47k
        }
553
338
        continue;
554
2.80k
      }
555
556
31.2k
      if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
557
31.2k
      proto_ce = lookup_class(proto_scope, proto_class_name);
558
31.2k
    } else {
559
      /* standard type */
560
773
      ZEND_ASSERT(!is_intersection);
561
773
      continue;
562
773
    }
563
564
31.2k
    if (!fe_ce || !proto_ce) {
565
29.8k
      have_unresolved = true;
566
29.8k
      continue;
567
29.8k
    }
568
1.41k
    if (unlinked_instanceof(fe_ce, proto_ce)) {
569
385
      track_class_dependency(fe_ce, fe_class_name);
570
385
      track_class_dependency(proto_ce, proto_class_name);
571
385
      if (!is_intersection) {
572
125
        return INHERITANCE_SUCCESS;
573
125
      }
574
1.02k
    } else {
575
1.02k
      if (is_intersection) {
576
333
        return INHERITANCE_ERROR;
577
333
      }
578
1.02k
    }
579
1.41k
  } 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
78.9k
static zend_string *get_class_from_type(const zend_class_entry *scope, const zend_type single_type) {
588
78.9k
  if (ZEND_TYPE_HAS_NAME(single_type)) {
589
75.3k
    return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
590
75.3k
  }
591
3.56k
  return NULL;
592
78.9k
}
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
10.0k
{
678
10.0k
  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
10.0k
  if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
683
230
      !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
684
227
    return INHERITANCE_SUCCESS;
685
227
  }
686
687
  /* Builtin types may be removed, but not added */
688
9.81k
  uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
689
9.81k
  uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
690
9.81k
  uint32_t added_types = fe_type_mask & ~proto_type_mask;
691
9.81k
  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
8.92k
  inheritance_status early_exit_status;
710
8.92k
  bool have_unresolved = false;
711
712
8.92k
  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
8.32k
  } 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
8.32k
    early_exit_status = INHERITANCE_ERROR;
730
8.32k
    const zend_type *single_type;
731
22.0k
    ZEND_TYPE_FOREACH(fe_type, single_type) {
732
22.0k
      inheritance_status status;
733
      /* Union has an intersection type as it's member */
734
22.0k
      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
10.3k
      } else {
738
10.3k
        zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
739
10.3k
        if (!fe_class_name) {
740
3.17k
          continue;
741
3.17k
        }
742
743
7.13k
        status = zend_is_class_subtype_of_type(
744
7.13k
          fe_scope, fe_class_name, proto_scope, proto_type);
745
7.13k
      }
746
747
10.5k
      if (status == early_exit_status) {
748
447
        return status;
749
447
      }
750
10.0k
      if (status == INHERITANCE_UNRESOLVED) {
751
5.98k
        have_unresolved = true;
752
5.98k
      }
753
10.0k
    } ZEND_TYPE_FOREACH_END();
754
8.32k
  }
755
756
8.44k
  if (!have_unresolved) {
757
5.90k
    return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
758
5.90k
  }
759
760
2.54k
  register_unresolved_classes(fe_scope, fe_type);
761
2.54k
  register_unresolved_classes(proto_scope, proto_type);
762
2.54k
  return INHERITANCE_UNRESOLVED;
763
8.44k
}
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
2.84k
{
769
2.84k
  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
288
    return INHERITANCE_SUCCESS;
772
288
  }
773
774
2.55k
  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.53k
  return zend_perform_covariant_type_check(
782
2.53k
    proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
783
2.55k
}
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
4.17k
{
793
4.17k
  uint32_t num_args, proto_num_args, fe_num_args;
794
4.17k
  inheritance_status status, local_status;
795
4.17k
  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
4.17k
  ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
801
4.17k
    && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
802
4.17k
      && (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
4.17k
  ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
807
4.17k
      || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
808
809
  /* The number of required arguments cannot increase. */
810
4.17k
  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
4.08k
  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
3.96k
  proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
821
3.96k
  fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
822
823
  /* A variadic function cannot become non-variadic */
824
3.96k
  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
3.96k
  proto_num_args = proto->common.num_args + proto_is_variadic;
830
3.96k
  fe_num_args = fe->common.num_args + fe_is_variadic;
831
3.96k
  num_args = MAX(proto_num_args, fe_num_args);
832
833
3.96k
  status = INHERITANCE_SUCCESS;
834
7.57k
  for (uint32_t i = 0; i < num_args; i++) {
835
3.92k
    zend_arg_info *proto_arg_info =
836
3.92k
      i < proto_num_args ? &proto->common.arg_info[i] :
837
3.92k
      proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
838
3.92k
    zend_arg_info *fe_arg_info =
839
3.92k
      i < fe_num_args ? &fe->common.arg_info[i] :
840
3.92k
      fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
841
3.92k
    if (!proto_arg_info) {
842
      /* A new (optional) argument has been added, which is fine. */
843
970
      continue;
844
970
    }
845
2.95k
    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
2.84k
    local_status = zend_do_perform_arg_type_hint_check(
853
2.84k
      fe_scope, fe_arg_info, proto_scope, proto_arg_info);
854
855
2.84k
    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
2.66k
    if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
865
24
      return INHERITANCE_ERROR;
866
24
    }
867
2.66k
  }
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
3.65k
  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
3.24k
    if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
874
481
      if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
875
243
        return INHERITANCE_ERROR;
876
243
      }
877
238
      if (status == INHERITANCE_SUCCESS) {
878
238
        return INHERITANCE_WARNING;
879
238
      }
880
0
      return status;
881
238
    }
882
883
2.76k
    local_status = zend_perform_covariant_type_check(
884
2.76k
      fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
885
886
2.76k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
887
1.13k
      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.13k
      return local_status;
892
1.13k
    }
893
2.76k
  }
894
895
2.03k
  return status;
896
3.65k
}
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.00k
{
902
4.00k
  if (ZEND_TYPE_IS_SET(arg_info->type)) {
903
3.46k
    zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
904
3.46k
    smart_str_append(str, type_str);
905
3.46k
    zend_string_release(type_str);
906
3.46k
    if (!return_hint) {
907
2.37k
      smart_str_appendc(str, ' ');
908
2.37k
    }
909
3.46k
  }
910
4.00k
}
911
/* }}} */
912
913
static ZEND_COLD zend_string *zend_get_function_declaration(
914
    const zend_function *fptr, zend_class_entry *scope) /* {{{ */
915
1.50k
{
916
1.50k
  smart_str str = {0};
917
918
1.50k
  if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
919
513
    smart_str_appendc(&str, '&');
920
513
  }
921
922
1.50k
  if (fptr->common.scope) {
923
1.50k
    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.50k
    } else {
927
1.50k
      smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), ZSTR_LEN(fptr->common.scope->name));
928
1.50k
    }
929
1.50k
    smart_str_appends(&str, "::");
930
1.50k
  }
931
932
1.50k
  smart_str_append(&str, fptr->common.function_name);
933
1.50k
  smart_str_appendc(&str, '(');
934
935
1.50k
  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.31k
    for (uint32_t i = 0; i < num_args;) {
945
2.91k
      zend_append_type_hint(&str, scope, arg_info, false);
946
947
2.91k
      if (ZEND_ARG_SEND_MODE(arg_info)) {
948
72
        smart_str_appendc(&str, '&');
949
72
      }
950
951
2.91k
      if (ZEND_ARG_IS_VARIADIC(arg_info)) {
952
4
        smart_str_appends(&str, "...");
953
4
      }
954
955
2.91k
      smart_str_appendc(&str, '$');
956
2.91k
      smart_str_append(&str, arg_info->name);
957
958
2.91k
      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.91k
      if (++i < num_args) {
1030
1.68k
        smart_str_appends(&str, ", ");
1031
1.68k
      }
1032
2.91k
      arg_info++;
1033
2.91k
    }
1034
1.40k
  }
1035
1036
1.50k
  smart_str_appendc(&str, ')');
1037
1038
1.50k
  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.50k
  smart_str_0(&str);
1043
1044
1.50k
  return str.s;
1045
1.50k
}
1046
/* }}} */
1047
1048
758
static zend_always_inline zend_string *func_filename(const zend_function *fn) {
1049
758
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
1050
758
}
1051
1052
758
static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
1053
758
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
1054
758
}
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
754
    inheritance_status status) {
1060
754
  zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
1061
754
  zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
1062
754
  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
754
  } else if (status == INHERITANCE_WARNING) {
1075
394
    const zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
1076
394
      child->common.attributes,
1077
394
      "returntypewillchange",
1078
394
      sizeof("returntypewillchange")-1
1079
394
    );
1080
1081
394
    if (!return_type_will_change_attribute) {
1082
393
      zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1083
393
        "Return type of %s should either be compatible with %s, "
1084
393
        "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1085
393
        ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1086
393
      ZEND_ASSERT(!EG(exception));
1087
393
    }
1088
394
  } 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
754
  zend_string_efree(child_prototype);
1094
754
  zend_string_efree(parent_prototype);
1095
754
}
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
1.74k
{
1102
1.74k
  inheritance_status status =
1103
1.74k
    zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1104
1.74k
  if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
1105
755
    if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
1106
1
      add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1107
754
    } else {
1108
754
      ZEND_ASSERT(status == INHERITANCE_ERROR || status == INHERITANCE_WARNING);
1109
754
      emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1110
754
    }
1111
755
  }
1112
1.74k
}
1113
1114
3.82k
#define ZEND_INHERITANCE_LAZY_CHILD_CLONE     (1<<0)
1115
6.98k
#define ZEND_INHERITANCE_CHECK_SILENT         (1<<1) /* don't throw errors */
1116
23.0k
#define ZEND_INHERITANCE_CHECK_PROTO          (1<<2) /* check method prototype (it might be already checked before) */
1117
8.77k
#define ZEND_INHERITANCE_CHECK_VISIBILITY     (1<<3)
1118
7.09k
#define ZEND_INHERITANCE_SET_CHILD_CHANGED    (1<<4)
1119
7.02k
#define ZEND_INHERITANCE_SET_CHILD_PROTO      (1<<5)
1120
4.59k
#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
4.93k
{
1127
4.93k
  uint32_t child_flags;
1128
4.93k
  uint32_t parent_flags = parent->common.fn_flags;
1129
4.93k
  zend_function *proto;
1130
1131
4.93k
#define SEPARATE_METHOD() do { \
1132
1.77k
      if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1133
1.77k
       && 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
1.77k
       && !(child_scope->ce_flags & ZEND_ACC_TRAIT) \
1138
1.77k
       && 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
1.77k
    } while(0)
1146
1147
4.93k
  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
4.78k
  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
4.77k
  child_flags = child->common.fn_flags;
1166
  /* You cannot change from static to non static and vice versa.
1167
   */
1168
4.77k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1169
4.36k
   && 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
4.68k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1186
4.27k
   && 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
4.68k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_CHANGED)
1196
1.73k
   && (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
4.68k
  proto = parent->common.prototype ?
1202
4.20k
    parent->common.prototype : parent;
1203
1204
4.68k
  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
244
    if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1208
98
      return INHERITANCE_SUCCESS;
1209
98
    }
1210
146
    parent = proto;
1211
146
  }
1212
1213
4.59k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_PROTO)
1214
2.14k
   && child->common.prototype != proto) {
1215
1.73k
    SEPARATE_METHOD();
1216
1.73k
    child->common.prototype = proto;
1217
1.73k
  }
1218
1219
  /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1220
4.59k
  if ((flags & ZEND_INHERITANCE_CHECK_VISIBILITY)
1221
4.19k
      && (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
4.56k
  if (flags & ZEND_INHERITANCE_CHECK_PROTO) {
1231
4.17k
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1232
2.42k
      return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1233
2.42k
    }
1234
1.74k
    perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1235
1.74k
  }
1236
1237
2.14k
  if ((flags & ZEND_INHERITANCE_RESET_CHILD_OVERRIDE)
1238
1.78k
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1239
5
    SEPARATE_METHOD();
1240
5
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1241
5
  }
1242
1243
2.14k
#undef SEPARATE_METHOD
1244
1245
2.14k
  return INHERITANCE_SUCCESS;
1246
4.56k
}
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
22.3k
{
1251
22.3k
  zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1252
1253
22.3k
  if (child) {
1254
1.83k
    zend_function *func = (zend_function*)Z_PTR_P(child);
1255
1256
1.83k
    if (is_interface && UNEXPECTED(func == parent)) {
1257
      /* The same method in interface may be inherited few times */
1258
0
      return;
1259
0
    }
1260
1261
1.83k
    do_inheritance_check_on_method(
1262
1.83k
      func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1263
20.5k
  } else {
1264
1265
20.5k
    if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1266
55
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1267
55
    }
1268
1269
20.5k
    parent = zend_duplicate_function(parent, ce);
1270
1271
20.5k
    if (!is_interface) {
1272
20.4k
      _zend_hash_append_ptr(&ce->function_table, key, parent);
1273
20.4k
    } else {
1274
40
      zend_hash_add_new_ptr(&ce->function_table, key, parent);
1275
40
    }
1276
20.5k
  }
1277
22.3k
}
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.33k
) {
1377
1.33k
  zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
1378
1.33k
  zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;
1379
1380
1.33k
  if (child
1381
643
   && (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.33k
  if (!parent) {
1387
815
    return;
1388
815
  }
1389
1390
517
  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
404
  child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1408
1409
404
  uint32_t parent_flags = parent->common.fn_flags;
1410
404
  if (parent_flags & ZEND_ACC_PRIVATE) {
1411
0
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1412
0
    return;
1413
0
  }
1414
1415
404
  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
403
  do_inheritance_check_on_method(
1423
403
    child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
1424
403
    ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY
1425
403
      | ZEND_INHERITANCE_SET_CHILD_CHANGED | ZEND_INHERITANCE_SET_CHILD_PROTO
1426
403
      | 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
403
}
1432
1433
3.49k
static prop_variance prop_get_variance(const zend_property_info *prop_info) {
1434
3.49k
  bool unbacked = prop_info->flags & ZEND_ACC_VIRTUAL;
1435
3.49k
  if (unbacked && prop_info->hooks) {
1436
568
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1437
293
      return PROP_COVARIANT;
1438
293
    }
1439
275
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
1440
170
      return PROP_CONTRAVARIANT;
1441
170
    }
1442
275
  }
1443
3.03k
  return PROP_INVARIANT;
1444
3.49k
}
1445
1446
static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1447
3.64k
{
1448
3.64k
  zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1449
1450
3.64k
  if (UNEXPECTED(child)) {
1451
1.09k
    zend_property_info *child_info = Z_PTR_P(child);
1452
1.09k
    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1453
13
      child_info->flags |= ZEND_ACC_CHANGED;
1454
13
    }
1455
1.09k
    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.09k
    if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1460
1.08k
      if (!(parent_info->ce->ce_flags & ZEND_ACC_INTERFACE)) {
1461
1.08k
        child_info->prototype = parent_info->prototype;
1462
1.08k
      }
1463
1464
1.08k
      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.07k
      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.07k
      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.06k
      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.06k
      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
729
        bool use_child_prop = !parent_info->hooks && child_info->hooks;
1507
1508
729
        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
729
        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
729
        zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1520
729
        if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1521
560
          if (use_child_prop) {
1522
187
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1523
373
          } else {
1524
373
            int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1525
373
            ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1526
373
            ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1527
373
          }
1528
560
        } 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
729
        if (!use_child_prop) {
1538
542
          child_info->offset = parent_info->offset;
1539
542
        }
1540
729
        child_info->flags &= ~ZEND_ACC_VIRTUAL;
1541
729
      }
1542
1543
1.06k
      if (parent_info->hooks || child_info->hooks) {
1544
2.00k
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1545
1.33k
          inherit_property_hook(ce, parent_info, child_info, i);
1546
1.33k
        }
1547
671
      }
1548
1549
1.06k
      prop_variance variance = prop_get_variance(parent_info);
1550
1.06k
      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.06k
      if (child_info->ce == ce) {
1565
1.01k
        child_info->flags &= ~ZEND_ACC_OVERRIDE;
1566
1.01k
      }
1567
1.06k
    }
1568
2.55k
  } else {
1569
2.55k
    zend_function **hooks = parent_info->hooks;
1570
2.55k
    if (hooks) {
1571
108
      ce->num_hooked_props++;
1572
108
      if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1573
9
        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1574
9
      }
1575
108
    }
1576
1577
2.55k
    _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1578
2.55k
  }
1579
3.64k
}
1580
/* }}} */
1581
1582
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1583
3.38k
{
1584
3.38k
  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
3.38k
  ZEND_ASSERT(ce != iface);
1589
3.38k
}
1590
/* }}} */
1591
1592
static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1593
802
{
1594
  /* expects interface to be contained in ce's interface list already */
1595
802
  uint32_t i, ce_num, if_num = iface->num_interfaces;
1596
1597
802
  ce_num = ce->num_interfaces;
1598
1599
802
  if (ce->type == ZEND_INTERNAL_CLASS) {
1600
236
    ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1601
566
  } else {
1602
566
    ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1603
566
  }
1604
1605
  /* Inherit the interfaces, only if they're not already inherited by the class */
1606
4.05k
  while (if_num--) {
1607
3.25k
    zend_class_entry *entry = iface->interfaces[if_num];
1608
3.39k
    for (i = 0; i < ce_num; i++) {
1609
198
      if (ce->interfaces[i] == entry) {
1610
56
        break;
1611
56
      }
1612
198
    }
1613
3.25k
    if (i == ce_num) {
1614
3.20k
      ce->interfaces[ce->num_interfaces++] = entry;
1615
3.20k
    }
1616
3.25k
  }
1617
802
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1618
1619
  /* and now call the implementing handlers */
1620
4.00k
  while (ce_num < ce->num_interfaces) {
1621
3.20k
    do_implement_interface(ce, ce->interfaces[ce_num++]);
1622
3.20k
  }
1623
802
}
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
7.00k
{
1654
7.00k
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1655
7.00k
  zend_class_constant *c;
1656
1657
7.00k
  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
6.93k
  } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1662
6.90k
    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
6.90k
    if (ce->type & ZEND_INTERNAL_CLASS) {
1673
150
      c = pemalloc(sizeof(zend_class_constant), 1);
1674
150
      memcpy(c, parent_const, sizeof(zend_class_constant));
1675
150
      parent_const = c;
1676
150
    }
1677
6.90k
    _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1678
6.90k
  }
1679
7.00k
}
1680
/* }}} */
1681
1682
void zend_build_properties_info_table(zend_class_entry *ce)
1683
57.5k
{
1684
57.5k
  zend_property_info **table, *prop;
1685
57.5k
  size_t size;
1686
57.5k
  if (ce->default_properties_count == 0) {
1687
41.2k
    return;
1688
41.2k
  }
1689
1690
16.3k
  ZEND_ASSERT(ce->properties_info_table == NULL);
1691
16.3k
  size = sizeof(zend_property_info *) * ce->default_properties_count;
1692
16.3k
  if (ce->type == ZEND_USER_CLASS) {
1693
16.2k
    ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1694
16.2k
  } else {
1695
102
    ce->properties_info_table = table = pemalloc(size, 1);
1696
102
  }
1697
1698
  /* Dead slots may be left behind during inheritance. Make sure these are NULLed out. */
1699
16.3k
  memset(table, 0, size);
1700
1701
16.3k
  if (ce->parent && ce->parent->default_properties_count != 0) {
1702
965
    zend_property_info **parent_table = ce->parent->properties_info_table;
1703
965
    memcpy(
1704
965
      table, parent_table,
1705
965
      sizeof(zend_property_info *) * ce->parent->default_properties_count
1706
965
    );
1707
1708
    /* Child did not add any new properties, we are done */
1709
965
    if (ce->default_properties_count == ce->parent->default_properties_count) {
1710
411
      return;
1711
411
    }
1712
965
  }
1713
1714
72.2k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, prop) {
1715
72.2k
    if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0
1716
18.8k
     && !(prop->flags & ZEND_ACC_VIRTUAL)) {
1717
18.6k
      const zend_property_info *root_prop = prop->prototype;
1718
18.6k
      if (UNEXPECTED(root_prop->flags & ZEND_ACC_VIRTUAL)) {
1719
        /* Prototype is virtual, we need to manually hunt down the first backed property. */
1720
51
        root_prop = prop;
1721
51
        zend_class_entry *parent_ce;
1722
62
        while ((parent_ce = root_prop->ce->parent)) {
1723
62
          zend_property_info *parent_prop = zend_hash_find_ptr(&parent_ce->properties_info, key);
1724
62
          if (!parent_prop
1725
62
           || parent_prop->prototype != prop->prototype
1726
62
           || (parent_prop->flags & ZEND_ACC_VIRTUAL)) {
1727
51
            break;
1728
51
          }
1729
11
          root_prop = parent_prop;
1730
11
        }
1731
51
      }
1732
18.6k
      uint32_t prop_table_offset = OBJ_PROP_TO_NUM(root_prop->offset);
1733
18.6k
      table[prop_table_offset] = prop;
1734
18.6k
    }
1735
72.2k
  } ZEND_HASH_FOREACH_END();
1736
15.9k
}
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.02k
{
1740
2.02k
  if (!prop_info->hooks) {
1741
0
    return;
1742
0
  }
1743
2.02k
  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.02k
  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.01k
  if (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1757
616
   && !ZEND_TYPE_IS_SET(prop_info->type)
1758
358
   && Z_TYPE(ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]) == IS_UNDEF) {
1759
204
    ZVAL_NULL(&ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]);
1760
204
  }
1761
6.04k
  for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1762
4.03k
    const zend_function *func = prop_info->hooks[i];
1763
4.03k
    if (func) {
1764
2.29k
      if ((zend_property_hook_kind)i == ZEND_PROPERTY_HOOK_GET
1765
1.54k
       && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1766
215
       && !(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.29k
      if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
1772
454
        abstract_error = false;
1773
454
      }
1774
2.29k
    }
1775
4.03k
  }
1776
2.01k
  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.01k
  if ((prop_info->flags & ZEND_ACC_VIRTUAL)
1781
1.39k
   && (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.01k
}
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
944
{
1805
944
  ZEND_ASSERT(prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET] == func);
1806
1807
944
  zend_arg_info *value_arg_info = &func->op_array.arg_info[0];
1808
944
  if (!ZEND_TYPE_IS_SET(value_arg_info->type)) {
1809
547
    return INHERITANCE_SUCCESS;
1810
547
  }
1811
1812
397
  if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1813
0
    return INHERITANCE_ERROR;
1814
0
  }
1815
1816
397
  zend_class_entry *ce = prop_info->ce;
1817
397
  return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type);
1818
397
}
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
3.17k
{
1843
3.17k
  zend_property_info *property_info;
1844
3.17k
  zend_string *key;
1845
1846
3.17k
  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
3.17k
  } 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
3.16k
  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
3.16k
  if (ce->parent_name) {
1878
3.00k
    zend_string_release_ex(ce->parent_name, 0);
1879
3.00k
  }
1880
3.16k
  ce->parent = parent_ce;
1881
3.16k
  ce->default_object_handlers = parent_ce->default_object_handlers;
1882
3.16k
  ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1883
1884
  /* Inherit properties */
1885
3.16k
  if (parent_ce->default_properties_count) {
1886
1.02k
    zval *src, *dst, *end;
1887
1888
1.02k
    if (ce->default_properties_count) {
1889
509
      zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1890
509
      src = ce->default_properties_table + ce->default_properties_count;
1891
509
      end = table + parent_ce->default_properties_count;
1892
509
      dst = end + ce->default_properties_count;
1893
509
      ce->default_properties_table = table;
1894
686
      do {
1895
686
        dst--;
1896
686
        src--;
1897
686
        ZVAL_COPY_VALUE_PROP(dst, src);
1898
686
      } while (dst != end);
1899
509
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1900
509
      end = ce->default_properties_table;
1901
511
    } else {
1902
511
      end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1903
511
      dst = end + parent_ce->default_properties_count;
1904
511
      ce->default_properties_table = end;
1905
511
    }
1906
1.02k
    src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1907
1.02k
    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
916
    } else {
1923
2.54k
      do {
1924
2.54k
        dst--;
1925
2.54k
        src--;
1926
2.54k
        ZVAL_COPY_PROP(dst, src);
1927
2.54k
        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
2.54k
        continue;
1932
2.54k
      } while (dst != end);
1933
916
    }
1934
1.02k
    ce->default_properties_count += parent_ce->default_properties_count;
1935
1.02k
  }
1936
1937
3.16k
  if (parent_ce->default_static_members_count) {
1938
142
    zval *src, *dst, *end;
1939
1940
142
    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
52
      end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1955
52
      dst = end + parent_ce->default_static_members_count;
1956
52
      ce->default_static_members_table = end;
1957
52
    }
1958
142
    src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1959
279
    do {
1960
279
      dst--;
1961
279
      src--;
1962
279
      if (Z_TYPE_P(src) == IS_INDIRECT) {
1963
59
        ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1964
220
      } else {
1965
220
        ZVAL_INDIRECT(dst, src);
1966
220
      }
1967
279
      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
279
    } while (dst != end);
1972
142
    ce->default_static_members_count += parent_ce->default_static_members_count;
1973
142
    if (!ZEND_MAP_PTR(ce->static_members_table)) {
1974
142
      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
142
    }
1979
142
  }
1980
1981
10.2k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1982
10.2k
    if (property_info->ce == ce) {
1983
1.95k
      if (property_info->flags & ZEND_ACC_STATIC) {
1984
197
        property_info->offset += parent_ce->default_static_members_count;
1985
1.76k
      } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1986
1.09k
        property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1987
1.09k
      }
1988
1.95k
    }
1989
10.2k
  } ZEND_HASH_FOREACH_END();
1990
1991
3.16k
  if (zend_hash_num_elements(&parent_ce->properties_info)) {
1992
1.24k
    zend_hash_extend(&ce->properties_info,
1993
1.24k
      zend_hash_num_elements(&ce->properties_info) +
1994
1.24k
      zend_hash_num_elements(&parent_ce->properties_info), 0);
1995
1996
9.77k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1997
9.77k
      do_inherit_property(property_info, key, ce);
1998
9.77k
    } ZEND_HASH_FOREACH_END();
1999
1.24k
  }
2000
2001
3.16k
  if (ce->num_hooked_props) {
2002
3.06k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
2003
3.06k
      if (property_info->ce == ce && property_info->hooks) {
2004
740
        zend_verify_hooked_property(ce, property_info, key);
2005
740
      }
2006
3.06k
    } ZEND_HASH_FOREACH_END();
2007
334
  }
2008
2009
3.16k
  if (zend_hash_num_elements(&parent_ce->constants_table)) {
2010
1.01k
    zend_class_constant *c;
2011
2012
1.01k
    zend_hash_extend(&ce->constants_table,
2013
1.01k
      zend_hash_num_elements(&ce->constants_table) +
2014
1.01k
      zend_hash_num_elements(&parent_ce->constants_table), 0);
2015
2016
16.0k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
2017
16.0k
      do_inherit_class_constant(key, c, ce);
2018
16.0k
    } ZEND_HASH_FOREACH_END();
2019
1.01k
  }
2020
2021
3.16k
  if (zend_hash_num_elements(&parent_ce->function_table)) {
2022
1.86k
    zend_hash_extend(&ce->function_table,
2023
1.86k
      zend_hash_num_elements(&ce->function_table) +
2024
1.86k
      zend_hash_num_elements(&parent_ce->function_table), 0);
2025
1.86k
    uint32_t flags =
2026
1.86k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2027
1.86k
      ZEND_INHERITANCE_SET_CHILD_CHANGED |
2028
1.86k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2029
1.86k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2030
2031
1.86k
    if (!checked) {
2032
904
      flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2033
904
    }
2034
1.86k
    zend_function *func;
2035
47.4k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
2036
47.4k
      do_inherit_method(key, func, ce, false, flags);
2037
47.4k
    } ZEND_HASH_FOREACH_END();
2038
1.86k
  }
2039
2040
3.16k
  do_inherit_parent_constructor(ce);
2041
2042
3.16k
  if (ce->type == ZEND_INTERNAL_CLASS) {
2043
156
    if (parent_ce->num_interfaces) {
2044
156
      zend_do_inherit_interfaces(ce, parent_ce);
2045
156
    }
2046
2047
156
    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
2048
4
      ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
2049
4
    }
2050
156
  }
2051
3.16k
  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
3.16k
}
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
128
) {
2095
128
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2096
128
  if (zv == NULL) {
2097
56
    return true;
2098
56
  }
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
56
{
2142
56
  if (do_inherit_constant_check(ce, c, name)) {
2143
56
    zend_class_constant *ct;
2144
56
    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
56
    if (ce->type & ZEND_INTERNAL_CLASS) {
2155
56
      ct = pemalloc(sizeof(zend_class_constant), 1);
2156
56
      memcpy(ct, c, sizeof(zend_class_constant));
2157
56
      c = ct;
2158
56
    }
2159
56
    zend_hash_update_ptr(&ce->constants_table, name, c);
2160
56
  }
2161
56
}
2162
/* }}} */
2163
2164
static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2165
188
{
2166
188
  zend_function *func;
2167
188
  zend_string *key;
2168
188
  zend_class_constant *c;
2169
188
  uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2170
2171
188
  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
170
    flags |=
2175
170
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2176
170
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2177
170
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2178
170
  } else {
2179
18
    flags |=
2180
18
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2181
18
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2182
18
  }
2183
2184
488
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2185
488
    do_inherit_iface_constant(key, c, ce, iface);
2186
488
  } ZEND_HASH_FOREACH_END();
2187
2188
1.42k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2189
1.42k
    do_inherit_method(key, func, ce, true, flags);
2190
1.42k
  } ZEND_HASH_FOREACH_END();
2191
2192
188
  zend_hash_extend(&ce->properties_info,
2193
188
    zend_hash_num_elements(&ce->properties_info) +
2194
188
    zend_hash_num_elements(&iface->properties_info), 0);
2195
2196
188
  zend_property_info *prop;
2197
188
  ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2198
188
    do_inherit_property(prop, key, ce);
2199
188
  } ZEND_HASH_FOREACH_END();
2200
2201
188
  do_implement_interface(ce, iface);
2202
188
  if (iface->num_interfaces) {
2203
80
    zend_do_inherit_interfaces(ce, iface);
2204
80
  }
2205
188
}
2206
/* }}} */
2207
2208
ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2209
188
{
2210
188
  bool ignore = false;
2211
188
  uint32_t current_iface_num = ce->num_interfaces;
2212
188
  uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
2213
2214
188
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2215
2216
408
  for (uint32_t i = 0; i < ce->num_interfaces; i++) {
2217
220
    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
220
    } 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
220
  }
2228
188
  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
188
  } else {
2236
188
    if (ce->num_interfaces >= current_iface_num) {
2237
188
      if (ce->type == ZEND_INTERNAL_CLASS) {
2238
188
        ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2239
188
      } else {
2240
0
        ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2241
0
      }
2242
188
    }
2243
188
    ce->interfaces[ce->num_interfaces++] = iface;
2244
2245
188
    do_interface_implementation(ce, iface);
2246
188
  }
2247
188
}
2248
/* }}} */
2249
2250
static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
2251
0
{
2252
0
  uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2253
0
  uint32_t num_interfaces = num_parent_interfaces;
2254
0
  zend_string *key;
2255
0
  zend_class_constant *c;
2256
0
  uint32_t i;
2257
2258
0
  for (i = 0; i < ce->num_interfaces; i++) {
2259
0
    zend_class_entry *iface = interfaces[num_parent_interfaces + i];
2260
0
    if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2261
0
      add_dependency_obligation(ce, iface);
2262
0
    }
2263
0
    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
0
    for (uint32_t j = 0; j < num_interfaces; j++) {
2269
0
      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
0
    }
2287
0
    if (iface) {
2288
0
      interfaces[num_interfaces] = iface;
2289
0
      num_interfaces++;
2290
0
    }
2291
0
  }
2292
2293
0
  if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2294
0
    for (i = 0; i < ce->num_interfaces; i++) {
2295
0
      zend_string_release_ex(ce->interface_names[i].name, 0);
2296
0
      zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2297
0
    }
2298
0
    efree(ce->interface_names);
2299
0
  }
2300
2301
0
  ce->num_interfaces = num_interfaces;
2302
0
  ce->interfaces = interfaces;
2303
0
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2304
2305
0
  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
0
  for (; i < num_interfaces; i++) {
2311
0
    do_interface_implementation(ce, ce->interfaces[i]);
2312
0
  }
2313
0
}
2314
/* }}} */
2315
2316
2317
void zend_inheritance_check_override(const zend_class_entry *ce)
2318
57.4k
{
2319
57.4k
  if (ce->ce_flags & ZEND_ACC_TRAIT) {
2320
1.33k
    return;
2321
1.33k
  }
2322
2323
178k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *f) {
2324
178k
    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
178k
  } ZEND_HASH_FOREACH_END();
2333
2334
158k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
2335
158k
    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.3k
    if (prop->hooks) {
2343
5.56k
      for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2344
3.71k
        zend_function *f = prop->hooks[i];
2345
3.71k
        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.71k
      }
2354
1.85k
    }
2355
23.3k
  } ZEND_HASH_FOREACH_END();
2356
56.0k
}
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
0
{
2367
0
  zend_function *existing_fn = NULL;
2368
0
  zend_function *new_fn;
2369
2370
0
  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
0
  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
0
  } else {
2410
0
    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2411
0
    memcpy(new_fn, fn, sizeof(zend_op_array));
2412
0
    new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2413
0
  }
2414
0
  new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2415
2416
  /* Reassign method name, in case it is an alias. */
2417
0
  new_fn->common.function_name = name;
2418
0
  function_add_ref(new_fn);
2419
0
  fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2420
0
  zend_add_magic_method(ce, fn, key);
2421
0
}
2422
/* }}} */
2423
2424
static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2425
0
{
2426
0
  if (fn->common.scope->ce_flags & ZEND_ACC_TRAIT) {
2427
2428
0
    fn->common.scope = ce;
2429
2430
0
    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2431
0
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2432
0
    }
2433
0
    if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2434
0
      ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2435
0
    }
2436
0
  }
2437
0
}
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
0
{
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
0
  if (!(original_fn_flags & ZEND_ACC_FINAL)
2447
0
    && (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
0
}
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
0
{
2455
0
  zend_trait_alias  *alias, **alias_ptr;
2456
0
  zend_function      fn_copy;
2457
0
  int                i;
2458
2459
  /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2460
0
  if (ce->trait_aliases) {
2461
0
    alias_ptr = ce->trait_aliases;
2462
0
    alias = *alias_ptr;
2463
0
    i = 0;
2464
0
    while (alias) {
2465
      /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2466
0
      if (alias->alias != NULL
2467
0
        && fn->common.scope == aliases[i]
2468
0
        && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2469
0
      ) {
2470
0
        fn_copy = *fn;
2471
0
        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
0
        } else {
2474
0
          fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2475
0
        }
2476
2477
0
        zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2478
2479
0
        zend_string *lcname = zend_string_tolower(alias->alias);
2480
0
        zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2481
0
        zend_string_release_ex(lcname, 0);
2482
0
      }
2483
0
      alias_ptr++;
2484
0
      alias = *alias_ptr;
2485
0
      i++;
2486
0
    }
2487
0
  }
2488
2489
0
  if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2490
    /* is not in hashtable, thus, function is not to be excluded */
2491
0
    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
0
    if (ce->trait_aliases) {
2495
0
      alias_ptr = ce->trait_aliases;
2496
0
      alias = *alias_ptr;
2497
0
      i = 0;
2498
0
      while (alias) {
2499
        /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2500
0
        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
0
        ) {
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
0
        alias_ptr++;
2511
0
        alias = *alias_ptr;
2512
0
        i++;
2513
0
      }
2514
0
    }
2515
2516
0
    zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2517
2518
0
    zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2519
0
  }
2520
0
}
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
0
{
2525
0
  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
0
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2531
0
    if (traits[i] == trait) {
2532
0
      return i;
2533
0
    }
2534
0
  }
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
0
}
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
0
{
2542
0
  size_t i, j = 0;
2543
0
  zend_trait_precedence *cur_precedence;
2544
0
  zend_trait_method_reference *cur_method_ref;
2545
0
  zend_string *lc_trait_name;
2546
0
  zend_string *lcname;
2547
0
  HashTable **exclude_tables = NULL;
2548
0
  zend_class_entry **aliases = NULL;
2549
0
  zend_class_entry *trait;
2550
2551
  /* resolve class references */
2552
0
  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
0
  if (ce->trait_aliases) {
2622
0
    i = 0;
2623
0
    while (ce->trait_aliases[i]) {
2624
0
      i++;
2625
0
    }
2626
0
    aliases = ecalloc(i, sizeof(zend_class_entry*));
2627
0
    i = 0;
2628
0
    while (ce->trait_aliases[i]) {
2629
0
      const zend_trait_alias *cur_alias = ce->trait_aliases[i];
2630
0
      cur_method_ref = &ce->trait_aliases[i]->trait_method;
2631
0
      lcname = zend_string_tolower(cur_method_ref->method_name);
2632
0
      if (cur_method_ref->class_name) {
2633
        /* For all aliases with an explicit class name, resolve the class now. */
2634
0
        lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2635
0
        trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2636
0
        zend_string_release_ex(lc_trait_name, 0);
2637
0
        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
0
        zend_check_trait_usage(ce, trait, traits);
2641
0
        aliases[i] = trait;
2642
2643
        /* And, ensure that the referenced method is resolvable, too. */
2644
0
        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
0
      } 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
0
      zend_string_release_ex(lcname, 0);
2685
0
      i++;
2686
0
    }
2687
0
  }
2688
2689
0
  *exclude_tables_ptr = exclude_tables;
2690
0
  *aliases_ptr = aliases;
2691
0
}
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
0
{
2696
0
  uint32_t i;
2697
0
  zend_string *key;
2698
0
  zend_function *fn;
2699
2700
0
  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
0
  } else {
2721
0
    for (i = 0; i < ce->num_traits; i++) {
2722
0
      if (traits[i]) {
2723
0
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2724
0
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2725
0
          *contains_abstract_methods |= is_abstract;
2726
0
          if (verify_abstract != is_abstract) {
2727
0
            continue;
2728
0
          }
2729
0
          zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2730
0
        } ZEND_HASH_FOREACH_END();
2731
0
      }
2732
0
    }
2733
0
  }
2734
0
}
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
0
{
2814
0
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2815
0
    zend_string *constant_name;
2816
0
    zend_class_constant *constant;
2817
2818
0
    if (!traits[i]) {
2819
0
      continue;
2820
0
    }
2821
2822
0
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2823
0
      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
0
    } ZEND_HASH_FOREACH_END();
2850
0
  }
2851
0
}
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
0
{
2871
0
  zend_property_info *property_info;
2872
0
  const zend_property_info *colliding_prop;
2873
0
  zend_string* prop_name;
2874
0
  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
0
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2882
0
    if (!traits[i]) {
2883
0
      continue;
2884
0
    }
2885
0
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2886
0
      uint32_t flags = property_info->flags;
2887
2888
      /* next: check for conflicts with current class */
2889
0
      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
0
  }
3004
0
}
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
0
#define zend_update_inherited_handler(handler) do { \
3323
0
    if (ce->handler == (zend_function*)op_array) { \
3324
0
      ce->handler = (zend_function*)new_op_array; \
3325
0
    } \
3326
0
  } while (0)
3327
3328
static zend_op_array *zend_lazy_method_load(
3329
0
    const zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3330
0
  ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3331
0
  ZEND_ASSERT(op_array->scope == pce);
3332
0
  ZEND_ASSERT(op_array->prototype == NULL);
3333
0
  zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3334
0
  memcpy(new_op_array, op_array, sizeof(zend_op_array));
3335
0
  new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3336
0
  new_op_array->scope = ce;
3337
0
  ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3338
0
  ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3339
3340
0
  return new_op_array;
3341
0
}
3342
3343
static zend_class_entry *zend_lazy_class_load(const zend_class_entry *pce)
3344
0
{
3345
0
  zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3346
3347
0
  memcpy(ce, pce, sizeof(zend_class_entry));
3348
0
  ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3349
0
  ce->refcount = 1;
3350
0
  ce->inheritance_cache = NULL;
3351
0
  if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3352
0
    ZEND_MAP_PTR_NEW(ce->mutable_data);
3353
0
  } else {
3354
0
    ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3355
0
  }
3356
3357
  /* properties */
3358
0
  if (ce->default_properties_table) {
3359
0
    zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3360
0
    zval *src = ce->default_properties_table;
3361
0
    const zval *end = src + ce->default_properties_count;
3362
3363
0
    ce->default_properties_table = dst;
3364
0
    for (; src != end; src++, dst++) {
3365
0
      ZVAL_COPY_VALUE_PROP(dst, src);
3366
0
    }
3367
0
  }
3368
3369
  /* methods */
3370
0
  ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3371
0
  if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3372
0
    Bucket *p = emalloc(HT_SIZE(&ce->function_table));
3373
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3374
0
    HT_SET_DATA_ADDR(&ce->function_table, p);
3375
0
    p = ce->function_table.arData;
3376
0
    const Bucket *end = p + ce->function_table.nNumUsed;
3377
0
    for (; p != end; p++) {
3378
0
      zend_op_array *op_array = Z_PTR(p->val);
3379
0
      zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3380
3381
0
      zend_update_inherited_handler(constructor);
3382
0
      zend_update_inherited_handler(destructor);
3383
0
      zend_update_inherited_handler(clone);
3384
0
      zend_update_inherited_handler(__get);
3385
0
      zend_update_inherited_handler(__set);
3386
0
      zend_update_inherited_handler(__call);
3387
0
      zend_update_inherited_handler(__isset);
3388
0
      zend_update_inherited_handler(__unset);
3389
0
      zend_update_inherited_handler(__tostring);
3390
0
      zend_update_inherited_handler(__callstatic);
3391
0
      zend_update_inherited_handler(__debugInfo);
3392
0
      zend_update_inherited_handler(__serialize);
3393
0
      zend_update_inherited_handler(__unserialize);
3394
0
    }
3395
0
  }
3396
3397
  /* static members */
3398
0
  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
0
  ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3409
3410
  /* properties_info */
3411
0
  if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3412
0
    Bucket *p = emalloc(HT_SIZE(&ce->properties_info));
3413
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3414
0
    HT_SET_DATA_ADDR(&ce->properties_info, p);
3415
0
    p = ce->properties_info.arData;
3416
0
    const Bucket *end = p + ce->properties_info.nNumUsed;
3417
0
    for (; p != end; p++) {
3418
0
      zend_property_info *new_prop_info;
3419
3420
0
      const zend_property_info *prop_info = Z_PTR(p->val);
3421
0
      ZEND_ASSERT(prop_info->ce == pce);
3422
0
      ZEND_ASSERT(prop_info->prototype == prop_info);
3423
0
      new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3424
0
      Z_PTR(p->val) = new_prop_info;
3425
0
      memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3426
0
      new_prop_info->ce = ce;
3427
0
      new_prop_info->prototype = new_prop_info;
3428
      /* Deep copy the type information */
3429
0
      zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3430
0
      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
0
    }
3444
0
  }
3445
3446
  /* constants table */
3447
0
  if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3448
0
    Bucket *p = emalloc(HT_SIZE(&ce->constants_table));
3449
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3450
0
    HT_SET_DATA_ADDR(&ce->constants_table, p);
3451
0
    p = ce->constants_table.arData;
3452
0
    const Bucket *end = p + ce->constants_table.nNumUsed;
3453
0
    for (; p != end; p++) {
3454
0
      zend_class_constant *new_c;
3455
3456
0
      const zend_class_constant *c = Z_PTR(p->val);
3457
0
      ZEND_ASSERT(c->ce == pce);
3458
0
      new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3459
0
      Z_PTR(p->val) = new_c;
3460
0
      memcpy(new_c, c, sizeof(zend_class_constant));
3461
0
      new_c->ce = ce;
3462
0
    }
3463
0
  }
3464
3465
0
  return ce;
3466
0
}
3467
3468
#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
3469
7.11k
# define UPDATE_IS_CACHEABLE(ce) do { \
3470
7.11k
      if ((ce)->type == ZEND_USER_CLASS) { \
3471
5.96k
        is_cacheable &= (ce)->ce_flags; \
3472
5.96k
      } \
3473
7.11k
    } 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
0
{
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
0
  zend_class_entry *parent = NULL;
3487
0
  zend_class_entry **traits_and_interfaces = NULL;
3488
0
  zend_class_entry *proto = NULL;
3489
0
  zend_class_entry *orig_linking_class;
3490
0
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3491
0
  uint32_t i, j;
3492
0
  zval *zv;
3493
0
  ALLOCA_FLAG(use_heap)
3494
3495
0
  SET_ALLOCA_FLAG(use_heap);
3496
0
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3497
3498
0
  if (ce->parent_name) {
3499
0
    parent = zend_fetch_class_by_name(
3500
0
      ce->parent_name, lc_parent_name,
3501
0
      ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3502
0
    if (!parent) {
3503
0
      check_unrecoverable_load_failure(ce);
3504
0
      return NULL;
3505
0
    }
3506
0
    UPDATE_IS_CACHEABLE(parent);
3507
0
  }
3508
3509
0
  if (ce->num_traits || ce->num_interfaces) {
3510
0
    traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3511
3512
0
    for (i = 0; i < ce->num_traits; i++) {
3513
0
      zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3514
0
        ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
3515
0
      if (UNEXPECTED(trait == NULL)) {
3516
0
        free_alloca(traits_and_interfaces, use_heap);
3517
0
        return NULL;
3518
0
      }
3519
0
      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
0
      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
0
      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
0
      traits_and_interfaces[i] = trait;
3539
0
      if (trait) {
3540
0
        UPDATE_IS_CACHEABLE(trait);
3541
0
      }
3542
0
    }
3543
0
  }
3544
3545
0
  if (ce->num_interfaces) {
3546
0
    for (i = 0; i < ce->num_interfaces; i++) {
3547
0
      zend_class_entry *iface = zend_fetch_class_by_name(
3548
0
        ce->interface_names[i].name, ce->interface_names[i].lc_name,
3549
0
        ZEND_FETCH_CLASS_INTERFACE |
3550
0
        ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3551
0
      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
0
      traits_and_interfaces[ce->num_traits + i] = iface;
3557
0
      if (iface) {
3558
0
        UPDATE_IS_CACHEABLE(iface);
3559
0
      }
3560
0
    }
3561
0
  }
3562
3563
0
#ifndef ZEND_WIN32
3564
0
  if (ce->ce_flags & ZEND_ACC_ENUM) {
3565
    /* We will add internal methods. */
3566
0
    is_cacheable = false;
3567
0
  }
3568
0
#endif
3569
3570
0
  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
0
  bool orig_record_errors = EG(record_errors);
3592
0
  if (!orig_record_errors) {
3593
0
    zend_begin_record_errors();
3594
0
  }
3595
3596
0
  zend_try {
3597
0
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3598
      /* Lazy class loading */
3599
0
      ce = zend_lazy_class_load(ce);
3600
0
      zv = zend_hash_find_known_hash(CG(class_table), key);
3601
0
      Z_CE_P(zv) = ce;
3602
0
    } 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
0
    if (CG(unlinked_uses)) {
3611
0
      zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3612
0
    }
3613
3614
0
    orig_linking_class = CG(current_linking_class);
3615
0
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3616
3617
0
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3618
      /* Only register builtin enum methods during inheritance to avoid persisting them in
3619
       * opcache. */
3620
0
      zend_enum_register_funcs(ce);
3621
0
    }
3622
3623
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3624
    zend_link_hooked_object_iter(ce);
3625
#endif
3626
3627
0
    HashTable **trait_exclude_tables;
3628
0
    zend_class_entry **trait_aliases;
3629
0
    bool trait_contains_abstract_methods = false;
3630
0
    if (ce->num_traits) {
3631
0
      zend_traits_init_trait_structures(ce, traits_and_interfaces, &trait_exclude_tables, &trait_aliases);
3632
0
      zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods);
3633
0
      zend_do_traits_constant_binding(ce, traits_and_interfaces);
3634
0
      zend_do_traits_property_binding(ce, traits_and_interfaces);
3635
3636
0
      zend_function *fn;
3637
0
      ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3638
0
        zend_fixup_trait_method(fn, ce);
3639
0
      } ZEND_HASH_FOREACH_END();
3640
0
    }
3641
0
    if (parent) {
3642
0
      if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3643
0
        add_dependency_obligation(ce, parent);
3644
0
      }
3645
0
      zend_do_inheritance(ce, parent);
3646
0
    }
3647
0
    if (ce->num_traits) {
3648
0
      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
0
      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
0
      if (trait_aliases) {
3671
0
        efree(trait_aliases);
3672
0
      }
3673
0
    }
3674
0
    if (ce->num_interfaces) {
3675
      /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3676
0
      uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3677
0
      zend_class_entry **interfaces = emalloc(
3678
0
          sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3679
3680
0
      if (num_parent_interfaces) {
3681
0
        memcpy(interfaces, parent->interfaces,
3682
0
             sizeof(zend_class_entry *) * num_parent_interfaces);
3683
0
      }
3684
0
      memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3685
0
           sizeof(zend_class_entry *) * ce->num_interfaces);
3686
3687
0
      zend_do_implement_interfaces(ce, interfaces);
3688
0
    } else if (parent && parent->num_interfaces) {
3689
0
      zend_do_inherit_interfaces(ce, parent);
3690
0
    }
3691
0
    if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3692
0
      && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3693
0
        ) {
3694
0
      zend_verify_abstract_class(ce);
3695
0
    }
3696
0
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3697
0
      zend_verify_enum(ce);
3698
0
    }
3699
0
    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
0
    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
0
    zend_build_properties_info_table(ce);
3733
0
  } 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
0
  } zend_end_try();
3741
3742
0
  EG(record_errors) = orig_record_errors;
3743
3744
0
  if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3745
0
    zend_inheritance_check_override(ce);
3746
0
    ce->ce_flags |= ZEND_ACC_LINKED;
3747
0
  } 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
0
  if (!CG(current_linking_class)) {
3764
0
    is_cacheable = 0;
3765
0
  }
3766
0
  CG(current_linking_class) = orig_linking_class;
3767
3768
0
  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
0
  if (!orig_record_errors) {
3786
0
    zend_emit_recorded_errors();
3787
0
    zend_free_recorded_errors();
3788
0
  }
3789
0
  if (traits_and_interfaces) {
3790
0
    free_alloca(traits_and_interfaces, use_heap);
3791
0
  }
3792
3793
0
  if (ZSTR_HAS_CE_CACHE(ce->name)) {
3794
0
    ZSTR_SET_CE_CACHE(ce->name, ce);
3795
0
  }
3796
3797
0
  return ce;
3798
0
}
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.11k
{
3804
7.11k
  zend_string *key;
3805
7.11k
  zend_function *parent_func;
3806
7.11k
  const zend_property_info *parent_info;
3807
7.11k
  const zend_class_constant *parent_const;
3808
7.11k
  inheritance_status overall_status = INHERITANCE_SUCCESS;
3809
3810
76.3k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3811
76.3k
    zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3812
76.3k
    if (zv) {
3813
2.69k
      zend_function *child_func = Z_FUNC_P(zv);
3814
2.69k
      inheritance_status status =
3815
2.69k
        do_inheritance_check_on_method(
3816
2.69k
          child_func, child_func->common.scope,
3817
2.69k
          parent_func, parent_func->common.scope,
3818
2.69k
          ce, NULL,
3819
2.69k
          ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3820
2.69k
      if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3821
462
        overall_status = INHERITANCE_WARNING;
3822
2.22k
      } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3823
1.12k
        return status;
3824
1.12k
      }
3825
2.69k
    }
3826
76.3k
  } ZEND_HASH_FOREACH_END();
3827
3828
31.2k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3829
31.2k
    const zval *zv;
3830
31.2k
    if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3831
4.92k
      continue;
3832
4.92k
    }
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.0k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3847
23.0k
    const zval *zv;
3848
23.0k
    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.35k
    zv = zend_hash_find_known_hash(&ce->constants_table, key);
3853
6.35k
    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.35k
  } ZEND_HASH_FOREACH_END();
3864
3865
4.76k
  return overall_status;
3866
4.87k
}
3867
/* }}} */
3868
3869
6.04k
static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3870
6.04k
  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.04k
  if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3888
3.02k
    return true;
3889
3.02k
  }
3890
3.01k
  return false;
3891
6.04k
}
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.11k
{
3895
7.11k
  inheritance_status status;
3896
7.11k
  zend_class_entry *proto = NULL;
3897
7.11k
  zend_class_entry *orig_linking_class;
3898
3899
7.11k
  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.11k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3909
7.11k
  UPDATE_IS_CACHEABLE(parent_ce);
3910
7.11k
  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.11k
  orig_linking_class = CG(current_linking_class);
3927
7.11k
  CG(current_linking_class) = NULL;
3928
7.11k
  status = zend_can_early_bind(ce, parent_ce);
3929
7.11k
  CG(current_linking_class) = orig_linking_class;
3930
7.11k
  if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3931
6.04k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3932
      /* Lazy class loading */
3933
0
      ce = zend_lazy_class_load(ce);
3934
6.04k
    } 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.04k
    if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3941
3.01k
      return NULL;
3942
3.01k
    }
3943
3944
3.02k
    orig_linking_class = CG(current_linking_class);
3945
3.02k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3946
3947
3.02k
    bool orig_record_errors = EG(record_errors);
3948
3949
3.02k
    zend_try{
3950
3.02k
      CG(zend_lineno) = ce->info.user.line_start;
3951
3952
3.02k
      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.02k
      zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3961
3.02k
      if (parent_ce && parent_ce->num_interfaces) {
3962
566
        zend_do_inherit_interfaces(ce, parent_ce);
3963
566
      }
3964
3.02k
      zend_build_properties_info_table(ce);
3965
3.02k
      if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
3966
15
        zend_verify_abstract_class(ce);
3967
15
      }
3968
3.02k
      zend_inheritance_check_override(ce);
3969
3.02k
      ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3970
3.02k
      ce->ce_flags |= ZEND_ACC_LINKED;
3971
3972
2.55k
      CG(current_linking_class) = orig_linking_class;
3973
2.55k
    } 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.55k
    } zend_end_try();
3980
3981
2.55k
    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.55k
    if (!orig_record_errors) {
3999
0
      zend_emit_recorded_errors();
4000
0
      zend_free_recorded_errors();
4001
0
    }
4002
4003
2.55k
    if (ZSTR_HAS_CE_CACHE(ce->name)) {
4004
0
      ZSTR_SET_CE_CACHE(ce->name, ce);
4005
0
    }
4006
2.55k
    zend_observer_class_linked_notify(ce, lcname);
4007
4008
2.55k
    return ce;
4009
2.55k
  }
4010
1.07k
  return NULL;
4011
7.11k
}
4012
/* }}} */