Coverage Report

Created: 2026-06-02 06:40

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