Coverage Report

Created: 2026-02-14 06:52

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