Coverage Report

Created: 2025-12-31 07:28

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