Coverage Report

Created: 2026-06-02 06:37

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