Coverage Report

Created: 2025-09-27 06:26

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