Coverage Report

Created: 2025-06-13 06:43

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