Coverage Report

Created: 2026-06-02 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/Zend/zend_inheritance.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend Engine                                                          |
4
   +----------------------------------------------------------------------+
5
   | Copyright © Zend Technologies Ltd., a subsidiary company of          |
6
   |     Perforce Software, Inc., and Contributors.                       |
7
   +----------------------------------------------------------------------+
8
   | This source file is subject to the Modified BSD License that is      |
9
   | bundled with this package in the file LICENSE, and is available      |
10
   | through the World Wide Web at <https://www.php.net/license/>.        |
11
   |                                                                      |
12
   | SPDX-License-Identifier: BSD-3-Clause                                |
13
   +----------------------------------------------------------------------+
14
   | Authors: Andi Gutmans <andi@php.net>                                 |
15
   |          Zeev Suraski <zeev@php.net>                                 |
16
   +----------------------------------------------------------------------+
17
*/
18
19
#include "zend.h"
20
#include "zend_API.h"
21
#include "zend_compile.h"
22
#include "zend_execute.h"
23
#include "zend_inheritance.h"
24
#include "zend_interfaces.h"
25
#include "zend_closures.h"
26
#include "zend_smart_str.h"
27
#include "zend_operators.h"
28
#include "zend_exceptions.h"
29
#include "zend_enum.h"
30
#include "zend_attributes.h"
31
#include "zend_constants.h"
32
#include "zend_observer.h"
33
34
ZEND_API zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces) = NULL;
35
ZEND_API zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies) = NULL;
36
37
/* Unresolved means that class declarations that are currently not available are needed to
38
 * determine whether the inheritance is valid or not. At runtime UNRESOLVED should be treated
39
 * as an ERROR. */
40
typedef zend_inheritance_status inheritance_status;
41
42
typedef enum {
43
  PROP_INVARIANT,
44
  PROP_COVARIANT,
45
  PROP_CONTRAVARIANT,
46
} prop_variance;
47
48
static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce);
49
static void add_compatibility_obligation(
50
    zend_class_entry *ce, const zend_function *child_fn, zend_class_entry *child_scope,
51
    const zend_function *parent_fn, zend_class_entry *parent_scope);
52
static void add_property_compatibility_obligation(
53
    zend_class_entry *ce, const zend_property_info *child_prop,
54
    const zend_property_info *parent_prop, prop_variance variance);
55
static void add_class_constant_compatibility_obligation(
56
    zend_class_entry *ce, const zend_class_constant *child_const,
57
    const zend_class_constant *parent_const, const zend_string *const_name);
58
static void add_property_hook_obligation(
59
    zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func);
60
61
static void ZEND_COLD emit_incompatible_method_error(
62
    const zend_function *child, const zend_class_entry *child_scope,
63
    const zend_function *parent, const zend_class_entry *parent_scope,
64
    inheritance_status status);
65
66
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent);
67
68
static void zend_type_list_copy_ctor(
69
  zend_type *const parent_type,
70
  bool use_arena,
71
  bool persistent
72
16
) {
73
16
  const zend_type_list *const old_list = ZEND_TYPE_LIST(*parent_type);
74
16
  size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
75
16
  zend_type_list *new_list = use_arena
76
16
    ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
77
78
16
  memcpy(new_list, old_list, size);
79
16
  ZEND_TYPE_SET_LIST(*parent_type, new_list);
80
16
  if (use_arena) {
81
16
    ZEND_TYPE_FULL_MASK(*parent_type) |= _ZEND_TYPE_ARENA_BIT;
82
16
  }
83
84
16
  zend_type *list_type;
85
48
  ZEND_TYPE_LIST_FOREACH_MUTABLE(new_list, list_type) {
86
48
    zend_type_copy_ctor(list_type, use_arena, persistent);
87
48
  } ZEND_TYPE_LIST_FOREACH_END();
88
16
}
89
90
1.01k
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
91
1.01k
  if (ZEND_TYPE_HAS_LIST(*type)) {
92
16
    zend_type_list_copy_ctor(type, use_arena, persistent);
93
996
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
94
58
    zend_string_addref(ZEND_TYPE_NAME(*type));
95
58
  }
96
1.01k
}
97
98
static zend_function *zend_duplicate_internal_function(const zend_function *func, const zend_class_entry *ce) /* {{{ */
99
4.68k
{
100
4.68k
  zend_function *new_function;
101
102
4.68k
  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
2.35k
  } else {
106
2.33k
    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
107
2.33k
    memcpy(new_function, func, sizeof(zend_internal_function));
108
2.33k
    new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
109
2.33k
  }
110
4.68k
  if (EXPECTED(new_function->common.function_name)) {
111
4.68k
    zend_string_addref(new_function->common.function_name);
112
4.68k
  }
113
4.68k
  return new_function;
114
4.68k
}
115
/* }}} */
116
117
static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
118
5.88k
{
119
5.88k
  if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
120
4.68k
    return zend_duplicate_internal_function(func, ce);
121
4.68k
  } else {
122
1.19k
    if (func->op_array.refcount) {
123
969
      (*func->op_array.refcount)++;
124
969
    }
125
1.19k
    if (EXPECTED(func->op_array.function_name)) {
126
1.19k
      zend_string_addref(func->op_array.function_name);
127
1.19k
    }
128
1.19k
    return func;
129
1.19k
  }
130
5.88k
}
131
/* }}} */
132
133
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
134
1.97k
{
135
1.97k
  zend_class_entry *parent = ce->parent;
136
137
1.97k
  ZEND_ASSERT(parent != NULL);
138
139
  /* You cannot change create_object */
140
1.97k
  ce->create_object = parent->create_object;
141
142
  /* Inherit special functions if needed */
143
1.97k
  if (EXPECTED(!ce->get_iterator)) {
144
1.83k
    ce->get_iterator = parent->get_iterator;
145
1.83k
  }
146
1.97k
  if (EXPECTED(!ce->__get)) {
147
1.92k
    ce->__get = parent->__get;
148
1.92k
  }
149
1.97k
  if (EXPECTED(!ce->__set)) {
150
1.96k
    ce->__set = parent->__set;
151
1.96k
  }
152
1.97k
  if (EXPECTED(!ce->__unset)) {
153
1.96k
    ce->__unset = parent->__unset;
154
1.96k
  }
155
1.97k
  if (EXPECTED(!ce->__isset)) {
156
1.96k
    ce->__isset = parent->__isset;
157
1.96k
  }
158
1.97k
  if (EXPECTED(!ce->__call)) {
159
1.96k
    ce->__call = parent->__call;
160
1.96k
  }
161
1.97k
  if (EXPECTED(!ce->__callstatic)) {
162
1.96k
    ce->__callstatic = parent->__callstatic;
163
1.96k
  }
164
1.97k
  if (EXPECTED(!ce->__tostring)) {
165
1.95k
    ce->__tostring = parent->__tostring;
166
1.95k
  }
167
1.97k
  if (EXPECTED(!ce->clone)) {
168
1.97k
    ce->clone = parent->clone;
169
1.97k
  }
170
1.97k
  if (EXPECTED(!ce->__serialize)) {
171
1.97k
    ce->__serialize = parent->__serialize;
172
1.97k
  }
173
1.97k
  if (EXPECTED(!ce->__unserialize)) {
174
1.97k
    ce->__unserialize = parent->__unserialize;
175
1.97k
  }
176
1.97k
  if (EXPECTED(!ce->serialize)) {
177
1.97k
    ce->serialize = parent->serialize;
178
1.97k
  }
179
1.97k
  if (EXPECTED(!ce->unserialize)) {
180
1.97k
    ce->unserialize = parent->unserialize;
181
1.97k
  }
182
1.97k
  if (!ce->destructor) {
183
1.95k
    ce->destructor = parent->destructor;
184
1.95k
  }
185
1.97k
  if (EXPECTED(!ce->__debugInfo)) {
186
1.97k
    ce->__debugInfo = parent->__debugInfo;
187
1.97k
  }
188
189
1.97k
  if (ce->constructor) {
190
256
    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
256
    return;
196
256
  }
197
198
1.72k
  ce->constructor = parent->constructor;
199
1.72k
}
200
/* }}} */
201
202
const char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
203
90
{
204
90
  if (fn_flags & ZEND_ACC_PUBLIC) {
205
12
    return "public";
206
78
  } else if (fn_flags & ZEND_ACC_PRIVATE) {
207
56
    return "private";
208
56
  } else {
209
22
    ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
210
22
    return "protected";
211
22
  }
212
90
}
213
/* }}} */
214
215
static const char *zend_asymmetric_visibility_string(uint32_t fn_flags) /* {{{ */
216
2
{
217
2
  if (fn_flags & ZEND_ACC_PRIVATE_SET) {
218
0
    return "private(set)";
219
2
  } else if (fn_flags & ZEND_ACC_PROTECTED_SET) {
220
0
    return "protected(set)";
221
2
  } else {
222
2
    ZEND_ASSERT(!(fn_flags & ZEND_ACC_PUBLIC_SET));
223
2
    return "omitted";
224
2
  }
225
2
}
226
227
3.65k
static zend_string *resolve_class_name(const zend_class_entry *scope, zend_string *name) {
228
3.65k
  ZEND_ASSERT(scope);
229
3.65k
  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
3.65k
  } else if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_SELF))) {
236
18
    return scope->name;
237
3.64k
  } else {
238
3.64k
    return name;
239
3.64k
  }
240
3.65k
}
241
242
802
static bool class_visible(const zend_class_entry *ce) {
243
802
  if (ce->type == ZEND_INTERNAL_CLASS) {
244
94
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
245
708
  } else {
246
708
    ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
247
708
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
248
496
      || ce->info.user.filename == CG(compiled_filename);
249
708
  }
250
802
}
251
252
168
static zend_always_inline void register_unresolved_class(zend_string *name) {
253
  /* We'll autoload this class and process delayed variance obligations later. */
254
168
  if (!CG(delayed_autoloads)) {
255
60
    ALLOC_HASHTABLE(CG(delayed_autoloads));
256
60
    zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
257
60
  }
258
168
  zend_hash_add_empty_element(CG(delayed_autoloads), name);
259
168
}
260
261
static zend_class_entry *lookup_class_ex(
262
2.86k
    zend_class_entry *scope, zend_string *name, bool register_unresolved) {
263
2.86k
  zend_class_entry *ce;
264
2.86k
  bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
265
266
2.86k
  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
2.82k
  ce = zend_lookup_class_ex(
283
2.82k
      name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
284
285
2.82k
  if (!CG(in_compilation) || in_preload) {
286
1.36k
    if (ce) {
287
902
      return ce;
288
902
    }
289
290
462
    if (register_unresolved) {
291
168
      register_unresolved_class(name);
292
168
    }
293
1.45k
  } else {
294
1.45k
    if (ce && class_visible(ce)) {
295
802
      return ce;
296
802
    }
297
298
    /* The current class may not be registered yet, so check for it explicitly. */
299
654
    if (zend_string_equals_ci(scope->name, name)) {
300
20
      return scope;
301
20
    }
302
654
  }
303
304
1.09k
  return NULL;
305
2.82k
}
306
307
2.16k
static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name) {
308
2.16k
  return lookup_class_ex(scope, name, /* register_unresolved */ false);
309
2.16k
}
310
311
/* Instanceof that's safe to use on unlinked classes. */
312
660
static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) {
313
660
  if (ce1 == ce2) {
314
80
    return true;
315
80
  }
316
317
580
  if (ce1->ce_flags & ZEND_ACC_LINKED) {
318
508
    return instanceof_function(ce1, ce2);
319
508
  }
320
321
72
  if (ce1->parent) {
322
68
    const zend_class_entry *parent_ce;
323
68
    if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
324
40
      parent_ce = ce1->parent;
325
40
    } else {
326
28
      parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
327
28
        ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
328
28
    }
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
68
    if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
333
54
      return true;
334
54
    }
335
68
  }
336
337
18
  if (ce1->num_interfaces) {
338
12
    uint32_t i;
339
12
    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
4
      for (i = 0; i < ce1->num_interfaces; i++) {
343
4
        if (unlinked_instanceof(ce1->interfaces[i], ce2)) {
344
4
          return true;
345
4
        }
346
4
      }
347
8
    } else {
348
12
      for (i = 0; i < ce1->num_interfaces; i++) {
349
10
        const zend_class_entry *ce = zend_lookup_class_ex(
350
10
          ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
351
10
          ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
352
        /* Avoid recursing if class implements itself. */
353
10
        if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
354
6
          return true;
355
6
        }
356
10
      }
357
8
    }
358
12
  }
359
360
8
  return false;
361
18
}
362
363
static bool zend_type_permits_self(
364
36
    const zend_type type, const zend_class_entry *scope, zend_class_entry *self) {
365
36
  if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
366
6
    return true;
367
6
  }
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
30
  const zend_type *single_type;
373
72
  ZEND_TYPE_FOREACH(type, single_type) {
374
72
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
375
42
      zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
376
42
      const zend_class_entry *ce = lookup_class(self, name);
377
42
      if (ce && unlinked_instanceof(self, ce)) {
378
26
        return true;
379
26
      }
380
42
    }
381
72
  } ZEND_TYPE_FOREACH_END();
382
4
  return false;
383
30
}
384
385
static void track_class_dependency(zend_class_entry *ce, zend_string *class_name)
386
622
{
387
622
  HashTable *ht;
388
389
622
  ZEND_ASSERT(class_name);
390
622
  if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
391
202
    return;
392
420
  } else if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_SELF))
393
420
          || zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_PARENT))) {
394
0
    return;
395
0
  }
396
397
420
#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
420
  if (ce->type == ZEND_INTERNAL_CLASS) {
401
62
    return;
402
62
  }
403
358
#endif
404
405
358
  ht = (HashTable*)CG(current_linking_class)->inheritance_cache;
406
407
358
  if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
408
    // TODO: dependency on not-immutable class ???
409
14
    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
14
    CG(current_linking_class)->ce_flags &= ~ZEND_ACC_CACHEABLE;
415
14
    CG(current_linking_class) = NULL;
416
14
    return;
417
14
  }
418
419
  /* Record dependency */
420
344
  if (!ht) {
421
64
    ALLOC_HASHTABLE(ht);
422
64
    zend_hash_init(ht, 0, NULL, NULL, 0);
423
64
    CG(current_linking_class)->inheritance_cache = (zend_inheritance_cache_entry*)ht;
424
64
  }
425
344
  zend_hash_add_ptr(ht, class_name, ce);
426
344
}
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
328
{
433
328
  ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(fe_type));
434
328
  bool have_unresolved = false;
435
328
  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
892
  ZEND_TYPE_FOREACH(fe_type, single_type) {
440
892
    zend_class_entry *fe_ce;
441
892
    zend_string *fe_class_name = NULL;
442
892
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
443
564
      fe_class_name =
444
564
        resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
445
564
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
446
196
        return INHERITANCE_SUCCESS;
447
196
      }
448
449
368
      if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
450
368
      fe_ce = lookup_class(fe_scope, fe_class_name);
451
368
    } 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
368
    if (!fe_ce || !proto_ce) {
459
210
      have_unresolved = true;
460
210
      continue;
461
210
    }
462
158
    if (unlinked_instanceof(fe_ce, proto_ce)) {
463
4
      track_class_dependency(fe_ce, fe_class_name);
464
4
      track_class_dependency(proto_ce, proto_class_name);
465
4
      return INHERITANCE_SUCCESS;
466
4
    }
467
158
  } ZEND_TYPE_FOREACH_END();
468
469
128
  return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
470
328
}
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
1.01k
    zend_class_entry *proto_scope, const zend_type proto_type) {
476
1.01k
  zend_class_entry *fe_ce = NULL;
477
1.01k
  bool have_unresolved = false;
478
479
  /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
480
1.01k
  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
56
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
485
56
    if (!fe_ce) {
486
24
      have_unresolved = true;
487
32
    } else {
488
32
      track_class_dependency(fe_ce, fe_class_name);
489
32
      return INHERITANCE_SUCCESS;
490
32
    }
491
56
  }
492
493
  /* If the parent has 'callable' as a return type, then Closure satisfies the co-variant check */
494
978
  if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_CALLABLE) {
495
2
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
496
2
    if (!fe_ce) {
497
0
      have_unresolved = true;
498
2
    } else if (fe_ce == zend_ce_closure) {
499
0
      track_class_dependency(fe_ce, fe_class_name);
500
0
      return INHERITANCE_SUCCESS;
501
0
    }
502
2
  }
503
504
  /* If the parent has 'static' as a return type, then final classes could replace it with self */
505
978
  if ((ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_STATIC) && (fe_scope->ce_flags & ZEND_ACC_FINAL)) {
506
36
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
507
36
    if (!fe_ce) {
508
4
      have_unresolved = true;
509
32
    } else if (fe_ce == fe_scope) {
510
24
      track_class_dependency(fe_ce, fe_class_name);
511
24
      return INHERITANCE_SUCCESS;
512
24
    }
513
36
  }
514
515
954
  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
954
  bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
520
2.19k
  ZEND_TYPE_FOREACH(proto_type, single_type) {
521
2.19k
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
522
84
      inheritance_status subtype_status = zend_is_class_subtype_of_type(
523
84
        fe_scope, fe_class_name, proto_scope, *single_type);
524
525
84
      switch (subtype_status) {
526
28
        case INHERITANCE_ERROR:
527
28
          if (is_intersection) {
528
0
            return INHERITANCE_ERROR;
529
0
          }
530
28
          continue;
531
32
        case INHERITANCE_UNRESOLVED:
532
32
          have_unresolved = true;
533
32
          continue;
534
24
        case INHERITANCE_SUCCESS:
535
24
          if (!is_intersection) {
536
24
            return INHERITANCE_SUCCESS;
537
24
          }
538
0
          continue;
539
0
        default: ZEND_UNREACHABLE();
540
84
      }
541
84
    }
542
543
1.16k
    zend_class_entry *proto_ce;
544
1.16k
    zend_string *proto_class_name = NULL;
545
1.16k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
546
1.09k
      proto_class_name =
547
1.09k
        resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
548
1.09k
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
549
374
        if (!is_intersection) {
550
370
          return INHERITANCE_SUCCESS;
551
370
        }
552
4
        continue;
553
374
      }
554
555
716
      if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
556
716
      proto_ce = lookup_class(proto_scope, proto_class_name);
557
716
    } else {
558
      /* standard type */
559
70
      ZEND_ASSERT(!is_intersection);
560
70
      continue;
561
70
    }
562
563
716
    if (!fe_ce || !proto_ce) {
564
314
      have_unresolved = true;
565
314
      continue;
566
314
    }
567
402
    if (unlinked_instanceof(fe_ce, proto_ce)) {
568
276
      track_class_dependency(fe_ce, fe_class_name);
569
276
      track_class_dependency(proto_ce, proto_class_name);
570
276
      if (!is_intersection) {
571
154
        return INHERITANCE_SUCCESS;
572
154
      }
573
276
    } else {
574
126
      if (is_intersection) {
575
30
        return INHERITANCE_ERROR;
576
30
      }
577
126
    }
578
402
  } ZEND_TYPE_FOREACH_END();
579
580
376
  if (have_unresolved) {
581
228
    return INHERITANCE_UNRESOLVED;
582
228
  }
583
148
  return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
584
376
}
585
586
4.18k
static zend_string *get_class_from_type(const zend_class_entry *scope, const zend_type single_type) {
587
4.18k
  if (ZEND_TYPE_HAS_NAME(single_type)) {
588
1.26k
    return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
589
1.26k
  }
590
2.92k
  return NULL;
591
4.18k
}
592
593
552
static void register_unresolved_classes(zend_class_entry *scope, const zend_type type) {
594
552
  const zend_type *single_type;
595
1.32k
  ZEND_TYPE_FOREACH(type, single_type) {
596
1.32k
    if (ZEND_TYPE_HAS_LIST(*single_type)) {
597
52
      register_unresolved_classes(scope, *single_type);
598
52
      continue;
599
52
    }
600
720
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
601
696
      zend_string *class_name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
602
696
      lookup_class_ex(scope, class_name, /* register_unresolved */ true);
603
696
    }
604
720
  } ZEND_TYPE_FOREACH_END();
605
552
}
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
248
{
611
248
  bool have_unresolved = false;
612
248
  const zend_type *single_type;
613
248
  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
248
  if (proto_type_mask & MAY_BE_OBJECT) {
620
18
    ZEND_TYPE_FOREACH(fe_type, single_type) {
621
18
      zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
622
18
      if (!fe_class_name) {
623
0
        continue;
624
0
      }
625
12
      zend_class_entry *fe_ce = lookup_class(fe_scope, fe_class_name);
626
12
      if (fe_ce) {
627
6
        track_class_dependency(fe_ce, fe_class_name);
628
6
        return INHERITANCE_SUCCESS;
629
6
      } else {
630
6
        have_unresolved = true;
631
6
      }
632
12
    } ZEND_TYPE_FOREACH_END();
633
6
  }
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
242
  inheritance_status early_exit_status =
640
242
    ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
641
616
  ZEND_TYPE_FOREACH(proto_type, single_type) {
642
616
    inheritance_status status;
643
644
616
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
645
42
      status = zend_is_intersection_subtype_of_type(
646
42
        fe_scope, fe_type, proto_scope, *single_type);
647
332
    } else {
648
332
      zend_string *proto_class_name = get_class_from_type(proto_scope, *single_type);
649
332
      if (!proto_class_name) {
650
4
        continue;
651
4
      }
652
653
328
      zend_class_entry *proto_ce = NULL;
654
328
      status = zend_is_intersection_subtype_of_class(
655
328
        fe_scope, fe_type, proto_scope, proto_class_name, proto_ce);
656
328
    }
657
658
370
    if (status == early_exit_status) {
659
94
      return status;
660
94
    }
661
276
    if (status == INHERITANCE_UNRESOLVED) {
662
92
      have_unresolved = true;
663
92
    }
664
276
  } ZEND_TYPE_FOREACH_END();
665
666
148
  if (have_unresolved) {
667
76
    return INHERITANCE_UNRESOLVED;
668
76
  }
669
670
72
  return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
671
148
}
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
4.39k
{
677
4.39k
  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
4.39k
  if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
682
466
      !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
683
466
    return INHERITANCE_SUCCESS;
684
466
  }
685
686
  /* Builtin types may be removed, but not added */
687
3.92k
  uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
688
3.92k
  uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
689
3.92k
  uint32_t added_types = fe_type_mask & ~proto_type_mask;
690
3.92k
  if (added_types) {
691
108
    if ((added_types & MAY_BE_STATIC)
692
36
        && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
693
      /* Replacing type that accepts self with static is okay */
694
32
      added_types &= ~MAY_BE_STATIC;
695
32
    }
696
697
108
    if (added_types == MAY_BE_NEVER) {
698
      /* never is the bottom type */
699
6
      return INHERITANCE_SUCCESS;
700
6
    }
701
702
102
    if (added_types) {
703
      /* Otherwise adding new types is illegal */
704
70
      return INHERITANCE_ERROR;
705
70
    }
706
102
  }
707
708
3.84k
  inheritance_status early_exit_status;
709
3.84k
  bool have_unresolved = false;
710
711
3.84k
  if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
712
110
    early_exit_status =
713
110
      ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
714
110
    inheritance_status status = zend_is_intersection_subtype_of_type(
715
110
      fe_scope, fe_type, proto_scope, proto_type);
716
717
110
    if (status == early_exit_status) {
718
38
      return status;
719
38
    }
720
72
    if (status == INHERITANCE_UNRESOLVED) {
721
36
      have_unresolved = true;
722
36
    }
723
3.73k
  } 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
3.73k
    early_exit_status = INHERITANCE_ERROR;
729
3.73k
    const zend_type *single_type;
730
7.67k
    ZEND_TYPE_FOREACH(fe_type, single_type) {
731
7.67k
      inheritance_status status;
732
      /* Union has an intersection type as it's member */
733
7.67k
      if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
734
96
        status = zend_is_intersection_subtype_of_type(
735
96
          fe_scope, *single_type, proto_scope, proto_type);
736
3.84k
      } else {
737
3.84k
        zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
738
3.84k
        if (!fe_class_name) {
739
2.91k
          continue;
740
2.91k
        }
741
742
926
        status = zend_is_class_subtype_of_type(
743
926
          fe_scope, fe_class_name, proto_scope, proto_type);
744
926
      }
745
746
1.02k
      if (status == early_exit_status) {
747
98
        return status;
748
98
      }
749
924
      if (status == INHERITANCE_UNRESOLVED) {
750
228
        have_unresolved = true;
751
228
      }
752
924
    } ZEND_TYPE_FOREACH_END();
753
3.73k
  }
754
755
3.71k
  if (!have_unresolved) {
756
3.46k
    return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
757
3.46k
  }
758
759
250
  register_unresolved_classes(fe_scope, fe_type);
760
250
  register_unresolved_classes(proto_scope, proto_type);
761
250
  return INHERITANCE_UNRESOLVED;
762
3.71k
}
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
2.02k
{
768
2.02k
  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
1.19k
    return INHERITANCE_SUCCESS;
771
1.19k
  }
772
773
836
  if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
774
    /* Child defines a type, but parent doesn't, violates LSP */
775
12
    return INHERITANCE_ERROR;
776
12
  }
777
778
  /* Contravariant type check is performed as a covariant type check with swapped
779
   * argument order. */
780
824
  return zend_perform_covariant_type_check(
781
824
    proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
782
836
}
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
3.90k
{
792
3.90k
  uint32_t num_args, proto_num_args, fe_num_args;
793
3.90k
  inheritance_status status, local_status;
794
3.90k
  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
3.90k
  ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
800
3.90k
    && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
801
3.90k
      && (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
3.90k
  ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
806
3.90k
      || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
807
808
  /* The number of required arguments cannot increase. */
809
3.90k
  if (proto->common.required_num_args < fe->common.required_num_args) {
810
14
    return INHERITANCE_ERROR;
811
14
  }
812
813
  /* by-ref constraints on return values are covariant */
814
3.88k
  if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
815
42
    && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
816
4
    return INHERITANCE_ERROR;
817
4
  }
818
819
3.88k
  proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
820
3.88k
  fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
821
822
  /* A variadic function cannot become non-variadic */
823
3.88k
  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
3.88k
  proto_num_args = proto->common.num_args + proto_is_variadic;
829
3.88k
  fe_num_args = fe->common.num_args + fe_is_variadic;
830
3.88k
  num_args = MAX(proto_num_args, fe_num_args);
831
832
3.88k
  status = INHERITANCE_SUCCESS;
833
5.84k
  for (uint32_t i = 0; i < num_args; i++) {
834
2.09k
    zend_arg_info *proto_arg_info =
835
2.09k
      i < proto_num_args ? &proto->common.arg_info[i] :
836
2.09k
      proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
837
2.09k
    zend_arg_info *fe_arg_info =
838
2.09k
      i < fe_num_args ? &fe->common.arg_info[i] :
839
2.09k
      fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
840
2.09k
    if (!proto_arg_info) {
841
      /* A new (optional) argument has been added, which is fine. */
842
19
      continue;
843
19
    }
844
2.07k
    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
48
      return INHERITANCE_ERROR;
849
48
    }
850
851
2.02k
    local_status = zend_do_perform_arg_type_hint_check(
852
2.02k
      fe_scope, fe_arg_info, proto_scope, proto_arg_info);
853
854
2.02k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
855
128
      if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
856
76
        return INHERITANCE_ERROR;
857
76
      }
858
52
      ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
859
52
      status = INHERITANCE_UNRESOLVED;
860
52
    }
861
862
    /* by-ref constraints on arguments are invariant */
863
1.95k
    if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
864
4
      return INHERITANCE_ERROR;
865
4
    }
866
1.95k
  }
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
3.75k
  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
3.12k
    if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
873
20
      if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
874
2
        return INHERITANCE_ERROR;
875
2
      }
876
18
      if (status == INHERITANCE_SUCCESS) {
877
18
        return INHERITANCE_WARNING;
878
18
      }
879
0
      return status;
880
18
    }
881
882
3.10k
    local_status = zend_perform_covariant_type_check(
883
3.10k
      fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
884
885
3.10k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
886
226
      if (local_status == INHERITANCE_ERROR
887
96
          && ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
888
28
        local_status = INHERITANCE_WARNING;
889
28
      }
890
226
      return local_status;
891
226
    }
892
3.10k
  }
893
894
3.50k
  return status;
895
3.75k
}
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
596
{
901
596
  if (ZEND_TYPE_IS_SET(arg_info->type)) {
902
444
    zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
903
444
    smart_str_append(str, type_str);
904
444
    zend_string_release(type_str);
905
444
    if (!return_hint) {
906
206
      smart_str_appendc(str, ' ');
907
206
    }
908
444
  }
909
596
}
910
/* }}} */
911
912
static ZEND_COLD zend_string *zend_get_function_declaration(
913
    const zend_function *fptr, const zend_class_entry *scope) /* {{{ */
914
396
{
915
396
  smart_str str = {0};
916
917
396
  if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
918
8
    smart_str_appendc(&str, '&');
919
8
  }
920
921
396
  if (fptr->common.scope) {
922
396
    if (fptr->common.scope->ce_flags & ZEND_ACC_ANON_CLASS) {
923
      /* cut off on NULL byte ... class@anonymous */
924
2
      smart_str_appends(&str, ZSTR_VAL(fptr->common.scope->name));
925
394
    } else {
926
394
      smart_str_append(&str, fptr->common.scope->name);
927
394
    }
928
396
    smart_str_appends(&str, "::");
929
396
  }
930
931
396
  smart_str_append(&str, fptr->common.function_name);
932
396
  smart_str_appendc(&str, '(');
933
934
396
  if (fptr->common.arg_info) {
935
364
    uint32_t num_args, required;
936
364
    zend_arg_info *arg_info = fptr->common.arg_info;
937
938
364
    required = fptr->common.required_num_args;
939
364
    num_args = fptr->common.num_args;
940
364
    if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
941
12
      num_args++;
942
12
    }
943
722
    for (uint32_t i = 0; i < num_args;) {
944
358
      zend_append_type_hint(&str, scope, arg_info, false);
945
946
358
      if (ZEND_ARG_SEND_MODE(arg_info)) {
947
6
        smart_str_appendc(&str, '&');
948
6
      }
949
950
358
      if (ZEND_ARG_IS_VARIADIC(arg_info)) {
951
12
        smart_str_appends(&str, "...");
952
12
      }
953
954
358
      smart_str_appendc(&str, '$');
955
358
      smart_str_append(&str, arg_info->name);
956
957
358
      if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
958
106
        smart_str_appends(&str, " = ");
959
960
106
        if (fptr->type == ZEND_INTERNAL_FUNCTION) {
961
18
          if (arg_info->default_value) {
962
18
            smart_str_append(&str, arg_info->default_value);
963
18
          } else {
964
0
            smart_str_appends(&str, "<default>");
965
0
          }
966
88
        } else {
967
88
          zend_op *precv = NULL;
968
88
          {
969
88
            uint32_t idx  = i;
970
88
            zend_op *op = fptr->op_array.opcodes;
971
88
            const zend_op *end = op + fptr->op_array.last;
972
973
88
            ++idx;
974
478
            while (op < end) {
975
390
              if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
976
256
                  && op->op1.num == (zend_ulong)idx)
977
88
              {
978
88
                precv = op;
979
88
              }
980
390
              ++op;
981
390
            }
982
88
          }
983
88
          if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
984
88
            zval *zv = RT_CONSTANT(precv, precv->op2);
985
986
88
            if (Z_TYPE_P(zv) == IS_FALSE) {
987
2
              smart_str_appends(&str, "false");
988
86
            } else if (Z_TYPE_P(zv) == IS_TRUE) {
989
2
              smart_str_appends(&str, "true");
990
84
            } else if (Z_TYPE_P(zv) == IS_NULL) {
991
32
              smart_str_appends(&str, "null");
992
52
            } else if (Z_TYPE_P(zv) == IS_STRING) {
993
4
              smart_str_appendc(&str, '\'');
994
4
              smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
995
4
              if (Z_STRLEN_P(zv) > 10) {
996
2
                smart_str_appends(&str, "...");
997
2
              }
998
4
              smart_str_appendc(&str, '\'');
999
48
            } else if (Z_TYPE_P(zv) == IS_ARRAY) {
1000
2
              if (zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0) {
1001
0
                smart_str_appends(&str, "[]");
1002
2
              } else {
1003
2
                smart_str_appends(&str, "[...]");
1004
2
              }
1005
46
            } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
1006
34
              zend_ast *ast = Z_ASTVAL_P(zv);
1007
34
              if (ast->kind == ZEND_AST_CONSTANT) {
1008
16
                smart_str_append(&str, zend_ast_get_constant_name(ast));
1009
18
              } else if (ast->kind == ZEND_AST_CLASS_CONST
1010
16
               && ast->child[1]->kind == ZEND_AST_ZVAL
1011
16
               && Z_TYPE_P(zend_ast_get_zval(ast->child[1])) == IS_STRING) {
1012
16
                smart_str_append(&str, zend_ast_get_str(ast->child[0]));
1013
16
                smart_str_appends(&str, "::");
1014
16
                smart_str_append(&str, zend_ast_get_str(ast->child[1]));
1015
16
              } else {
1016
2
                smart_str_appends(&str, "<expression>");
1017
2
              }
1018
34
            } else {
1019
12
              zend_string *tmp_zv_str;
1020
12
              zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str);
1021
12
              smart_str_append(&str, zv_str);
1022
12
              zend_tmp_string_release(tmp_zv_str);
1023
12
            }
1024
88
          }
1025
88
        }
1026
106
      }
1027
1028
358
      if (++i < num_args) {
1029
142
        smart_str_appends(&str, ", ");
1030
142
      }
1031
358
      arg_info++;
1032
358
    }
1033
364
  }
1034
1035
396
  smart_str_appendc(&str, ')');
1036
1037
396
  if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1038
238
    smart_str_appends(&str, ": ");
1039
238
    zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, true);
1040
238
  }
1041
396
  smart_str_0(&str);
1042
1043
396
  return str.s;
1044
396
}
1045
/* }}} */
1046
1047
198
static zend_always_inline zend_string *func_filename(const zend_function *fn) {
1048
198
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
1049
198
}
1050
1051
198
static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
1052
198
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
1053
198
}
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
198
    inheritance_status status) {
1059
198
  zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
1060
198
  zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
1061
198
  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
34
    const zend_string *unresolved_class = NULL;
1065
34
    ZEND_HASH_MAP_FOREACH_STR_KEY(CG(delayed_autoloads), unresolved_class) {
1066
34
      break;
1067
102
    } ZEND_HASH_FOREACH_END();
1068
34
    ZEND_ASSERT(unresolved_class);
1069
1070
34
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1071
34
      "Could not check compatibility between %s and %s, because class %s is not available",
1072
34
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
1073
164
  } else if (status == INHERITANCE_WARNING) {
1074
34
    const zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
1075
34
      child->common.attributes,
1076
34
      "returntypewillchange",
1077
34
      sizeof("returntypewillchange")-1
1078
34
    );
1079
1080
34
    if (!return_type_will_change_attribute) {
1081
26
      zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1082
26
        "Return type of %s should either be compatible with %s, "
1083
26
        "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1084
26
        ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1085
26
      ZEND_ASSERT(!EG(exception));
1086
26
    }
1087
130
  } else {
1088
130
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1089
130
      "Declaration of %s must be compatible with %s",
1090
130
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1091
130
  }
1092
198
  zend_string_efree(child_prototype);
1093
198
  zend_string_efree(parent_prototype);
1094
198
}
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
3.22k
{
1101
3.22k
  inheritance_status status =
1102
3.22k
    zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1103
3.22k
  if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
1104
224
    if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
1105
64
      add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1106
160
    } else {
1107
160
      ZEND_ASSERT(status == INHERITANCE_ERROR || status == INHERITANCE_WARNING);
1108
160
      emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1109
160
    }
1110
224
  }
1111
3.22k
}
1112
1113
6.75k
#define ZEND_INHERITANCE_LAZY_CHILD_CLONE     (1<<0)
1114
4.63k
#define ZEND_INHERITANCE_CHECK_SILENT         (1<<1) /* don't throw errors */
1115
21.0k
#define ZEND_INHERITANCE_CHECK_PROTO          (1<<2) /* check method prototype (it might be already checked before) */
1116
7.38k
#define ZEND_INHERITANCE_CHECK_VISIBILITY     (1<<3)
1117
6.24k
#define ZEND_INHERITANCE_SET_CHILD_CHANGED    (1<<4)
1118
7.49k
#define ZEND_INHERITANCE_SET_CHILD_PROTO      (1<<5)
1119
7.06k
#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
4.63k
{
1126
4.63k
  uint32_t child_flags;
1127
4.63k
  uint32_t parent_flags = parent->common.fn_flags;
1128
4.63k
  zend_function *proto;
1129
1130
4.63k
#define SEPARATE_METHOD() do { \
1131
3.48k
      if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1132
3.48k
       && 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
3.48k
       && !(child_scope->ce_flags & ZEND_ACC_TRAIT) \
1137
3.48k
       && child->type == ZEND_USER_FUNCTION) { \
1138
        /* op_array wasn't duplicated yet */ \
1139
4
        zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); \
1140
4
        memcpy(new_function, child, sizeof(zend_op_array)); \
1141
4
        Z_PTR_P(child_zv) = child = new_function; \
1142
4
        flags &= ~ZEND_INHERITANCE_LAZY_CHILD_CLONE; \
1143
4
      } \
1144
3.48k
    } while(0)
1145
1146
4.63k
  if (UNEXPECTED((parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_ABSTRACT|ZEND_ACC_CTOR)) == ZEND_ACC_PRIVATE)) {
1147
116
    if (flags & ZEND_INHERITANCE_SET_CHILD_CHANGED) {
1148
64
      SEPARATE_METHOD();
1149
64
      child->common.fn_flags |= ZEND_ACC_CHANGED;
1150
64
    }
1151
    /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
1152
116
    return INHERITANCE_SUCCESS;
1153
116
  }
1154
1155
4.51k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO) && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
1156
4
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1157
0
      return INHERITANCE_ERROR;
1158
0
    }
1159
4
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1160
4
      "Cannot override final method %s::%s()",
1161
4
      ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
1162
4
  }
1163
1164
4.51k
  child_flags = child->common.fn_flags;
1165
  /* You cannot change from static to non static and vice versa.
1166
   */
1167
4.51k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1168
4.01k
   && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
1169
2
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1170
0
      return INHERITANCE_ERROR;
1171
0
    }
1172
2
    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
2
    } else {
1177
2
      zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1178
2
        "Cannot make static method %s::%s() non static in class %s",
1179
2
        ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1180
2
    }
1181
2
  }
1182
1183
  /* Disallow making an inherited method abstract. */
1184
4.51k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1185
4.01k
   && 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
4.51k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_CHANGED)
1195
1.08k
   && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
1196
2
    SEPARATE_METHOD();
1197
2
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1198
2
  }
1199
1200
4.51k
  proto = parent->common.prototype ?
1201
4.34k
    parent->common.prototype : parent;
1202
1203
4.51k
  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
312
    if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1207
264
      return INHERITANCE_SUCCESS;
1208
264
    }
1209
48
    parent = proto;
1210
48
  }
1211
1212
4.24k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_PROTO)
1213
3.47k
   && child->common.prototype != proto) {
1214
3.38k
    SEPARATE_METHOD();
1215
3.38k
    child->common.prototype = proto;
1216
3.38k
  }
1217
1218
  /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1219
4.24k
  if ((flags & ZEND_INHERITANCE_CHECK_VISIBILITY)
1220
3.76k
      && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1221
4
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1222
2
      return INHERITANCE_ERROR;
1223
2
    }
1224
2
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1225
2
      "Access level to %s::%s() must be %s (as in class %s)%s",
1226
2
      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
4
  }
1228
1229
4.24k
  if (flags & ZEND_INHERITANCE_CHECK_PROTO) {
1230
3.84k
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1231
623
      return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1232
623
    }
1233
3.22k
    perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1234
3.22k
  }
1235
1236
3.62k
  if ((flags & ZEND_INHERITANCE_RESET_CHILD_OVERRIDE)
1237
3.49k
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1238
32
    SEPARATE_METHOD();
1239
32
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1240
32
  }
1241
1242
3.62k
#undef SEPARATE_METHOD
1243
1244
3.62k
  return INHERITANCE_SUCCESS;
1245
4.24k
}
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
9.53k
{
1250
9.53k
  zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1251
1252
9.53k
  if (child) {
1253
3.67k
    zend_function *func = (zend_function*)Z_PTR_P(child);
1254
1255
3.67k
    if (is_interface && UNEXPECTED(func == parent)) {
1256
      /* The same method in interface may be inherited few times */
1257
0
      return;
1258
0
    }
1259
1260
3.67k
    do_inheritance_check_on_method(
1261
3.67k
      func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1262
5.85k
  } else {
1263
1264
5.85k
    if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1265
76
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1266
76
    }
1267
1268
5.85k
    parent = zend_duplicate_function(parent, ce);
1269
1270
5.85k
    if (!is_interface) {
1271
5.78k
      _zend_hash_append_ptr(&ce->function_table, key, parent);
1272
5.78k
    } else {
1273
74
      zend_hash_add_new_ptr(&ce->function_table, key, parent);
1274
74
    }
1275
5.85k
  }
1276
9.53k
}
1277
/* }}} */
1278
1279
static inheritance_status full_property_types_compatible(
1280
    const zend_property_info *parent_info, const zend_property_info *child_info,
1281
354
    prop_variance variance) {
1282
354
  if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
1283
328
      && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1284
242
    return INHERITANCE_SUCCESS;
1285
242
  }
1286
1287
112
  if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1288
0
    return INHERITANCE_ERROR;
1289
0
  }
1290
1291
  /* Perform a covariant type check in both directions to determined invariance. */
1292
112
  inheritance_status status1 = variance == PROP_CONTRAVARIANT ? INHERITANCE_SUCCESS :
1293
112
    zend_perform_covariant_type_check(
1294
104
      child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1295
112
  inheritance_status status2 = variance == PROP_COVARIANT ? INHERITANCE_SUCCESS :
1296
112
    zend_perform_covariant_type_check(
1297
106
      parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1298
112
  if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1299
64
    return INHERITANCE_SUCCESS;
1300
64
  }
1301
48
  if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1302
22
    return INHERITANCE_ERROR;
1303
22
  }
1304
26
  ZEND_ASSERT(status1 == INHERITANCE_UNRESOLVED || status2 == INHERITANCE_UNRESOLVED);
1305
26
  return INHERITANCE_UNRESOLVED;
1306
26
}
1307
1308
static ZEND_COLD void emit_incompatible_property_error(
1309
18
    const zend_property_info *child, const zend_property_info *parent, prop_variance variance) {
1310
18
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1311
18
  zend_error_noreturn(E_COMPILE_ERROR,
1312
18
    "Type of %s::$%s must be %s%s (as in class %s)",
1313
18
    ZSTR_VAL(child->ce->name),
1314
18
    zend_get_unmangled_property_name(child->name),
1315
18
    variance == PROP_INVARIANT ? "" :
1316
18
    variance == PROP_COVARIANT ? "subtype of " : "supertype of ",
1317
18
    ZSTR_VAL(type_str),
1318
18
    ZSTR_VAL(parent->ce->name));
1319
18
}
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
354
) {
1341
354
  inheritance_status result = full_property_types_compatible(parent_info, child_info, variance);
1342
354
  if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1343
18
    emit_incompatible_property_error(child_info, parent_info, variance);
1344
18
  }
1345
354
  if (result != INHERITANCE_SUCCESS) {
1346
30
    return result;
1347
30
  }
1348
324
  if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1349
70
    ZEND_ASSERT(parent_info->hooks);
1350
70
    if (parent_info->hooks[ZEND_PROPERTY_HOOK_SET]
1351
28
     && (!child_info->hooks || !child_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1352
12
      zend_type set_type = parent_info->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1353
12
      inheritance_status result = zend_perform_covariant_type_check(
1354
12
        parent_info->ce, set_type, child_info->ce, child_info->type);
1355
12
      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
12
    }
1359
70
  }
1360
324
  return INHERITANCE_SUCCESS;
1361
324
}
1362
1363
static bool property_has_operation(const zend_property_info *prop_info, zend_property_hook_kind kind)
1364
50
{
1365
50
  return (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1366
46
      && (kind == ZEND_PROPERTY_HOOK_GET || !(prop_info->flags & ZEND_ACC_READONLY)))
1367
6
    || (prop_info->hooks && prop_info->hooks[kind]);
1368
50
}
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
396
) {
1376
396
  zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
1377
396
  zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;
1378
1379
396
  if (child
1380
188
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)
1381
12
   && property_has_operation(parent_info, kind)) {
1382
10
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1383
10
  }
1384
1385
396
  if (!parent) {
1386
244
    return;
1387
244
  }
1388
1389
152
  if (!child) {
1390
64
    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
38
      if (property_has_operation(child_info, kind)) {
1393
36
        return;
1394
36
      }
1395
2
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1396
2
    }
1397
28
    if (!child_info->hooks) {
1398
14
      ce->num_hooked_props++;
1399
14
      child_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1400
14
      memset(child_info->hooks, 0, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1401
14
    }
1402
28
    child_info->hooks[kind] = zend_duplicate_function(parent, ce);
1403
28
    return;
1404
64
  }
1405
1406
88
  child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1407
1408
88
  uint32_t parent_flags = parent->common.fn_flags;
1409
88
  if (parent_flags & ZEND_ACC_PRIVATE) {
1410
0
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1411
0
    return;
1412
0
  }
1413
1414
88
  if (parent_flags & ZEND_ACC_FINAL) {
1415
2
    zend_error_noreturn(E_COMPILE_ERROR,
1416
2
      "Cannot override final property hook %s::%s()",
1417
2
      ZSTR_VAL(parent->common.scope->name),
1418
2
      ZSTR_VAL(parent->common.function_name));
1419
2
  }
1420
1421
86
  do_inheritance_check_on_method(
1422
86
    child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
1423
86
    ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY
1424
86
      | ZEND_INHERITANCE_SET_CHILD_CHANGED | ZEND_INHERITANCE_SET_CHILD_PROTO
1425
86
      | 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
86
}
1431
1432
505
static prop_variance prop_get_variance(const zend_property_info *prop_info) {
1433
505
  bool unbacked = prop_info->flags & ZEND_ACC_VIRTUAL;
1434
505
  if (unbacked && prop_info->hooks) {
1435
140
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1436
86
      return PROP_COVARIANT;
1437
86
    }
1438
54
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
1439
14
      return PROP_CONTRAVARIANT;
1440
14
    }
1441
54
  }
1442
405
  return PROP_INVARIANT;
1443
505
}
1444
1445
static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1446
2.60k
{
1447
2.60k
  zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1448
1449
2.60k
  if (UNEXPECTED(child)) {
1450
497
    zend_property_info *child_info = Z_PTR_P(child);
1451
497
    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1452
132
      child_info->flags |= ZEND_ACC_CHANGED;
1453
132
    }
1454
497
    if (parent_info->flags & ZEND_ACC_FINAL) {
1455
2
      zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final property %s::$%s",
1456
2
        ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key));
1457
2
    }
1458
495
    if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1459
367
      if (!(parent_info->ce->ce_flags & ZEND_ACC_INTERFACE)) {
1460
345
        child_info->prototype = parent_info->prototype;
1461
345
      }
1462
1463
367
      if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
1464
0
        zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1465
0
          (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1466
0
          (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
1467
0
      }
1468
367
      if (UNEXPECTED((child_info->flags & ZEND_ACC_READONLY) != (parent_info->flags & ZEND_ACC_READONLY))) {
1469
8
        if (!(parent_info->flags & ZEND_ACC_ABSTRACT)) {
1470
0
          zend_error_noreturn(E_COMPILE_ERROR,
1471
0
            "Cannot redeclare %s property %s::$%s as %s %s::$%s",
1472
0
            parent_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1473
0
            ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1474
0
            child_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1475
0
            ZSTR_VAL(ce->name), ZSTR_VAL(key));
1476
0
        }
1477
8
      }
1478
367
      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
40
       && !(parent_info->hooks && (parent_info->flags & ZEND_ACC_VIRTUAL) && !parent_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1481
22
        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
22
        if (!parent_set_visibility) {
1485
4
          parent_set_visibility = zend_visibility_to_set_visibility(parent_info->flags & ZEND_ACC_PPP_MASK);
1486
4
        }
1487
22
        uint32_t child_set_visibility = child_info->flags & ZEND_ACC_PPP_SET_MASK;
1488
22
        if (child_set_visibility > parent_set_visibility) {
1489
2
          zend_error_noreturn(
1490
2
            E_COMPILE_ERROR,
1491
2
            "Set access level of %s::$%s must be %s (as in class %s)%s",
1492
2
            ZSTR_VAL(ce->name), ZSTR_VAL(key),
1493
2
            zend_asymmetric_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name),
1494
2
            !(parent_info->flags & ZEND_ACC_PPP_SET_MASK) ? "" : " or weaker");
1495
2
        }
1496
22
      }
1497
1498
365
      if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1499
2
        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
2
      }
1501
363
      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
225
        bool use_child_prop = !parent_info->hooks && child_info->hooks;
1506
1507
225
        if (use_child_prop && child_info->offset == ZEND_VIRTUAL_PROPERTY_OFFSET) {
1508
40
          child_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
1509
40
          ce->default_properties_count++;
1510
40
          ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1511
40
          zval *property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(child_info->offset)];
1512
40
          ZVAL_UNDEF(property_default_ptr);
1513
40
          Z_PROP_FLAG_P(property_default_ptr) = IS_PROP_UNINIT;
1514
40
        }
1515
1516
225
        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
225
        zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1519
225
        if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1520
211
          if (use_child_prop) {
1521
78
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1522
133
          } else {
1523
133
            int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1524
133
            ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1525
133
            ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1526
133
          }
1527
211
        } else {
1528
          /* Default value was removed in child, remove it from parent too. */
1529
14
          if (ZEND_TYPE_IS_SET(child_info->type)) {
1530
8
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1531
8
          } else {
1532
6
            ZVAL_NULL(&ce->default_properties_table[parent_num]);
1533
6
          }
1534
14
        }
1535
1536
225
        if (!use_child_prop) {
1537
147
          child_info->offset = parent_info->offset;
1538
147
        }
1539
225
        child_info->flags &= ~ZEND_ACC_VIRTUAL;
1540
225
      }
1541
1542
363
      if (parent_info->hooks || child_info->hooks) {
1543
595
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1544
396
          inherit_property_hook(ce, parent_info, child_info, i);
1545
396
        }
1546
199
      }
1547
1548
363
      prop_variance variance = prop_get_variance(parent_info);
1549
363
      if (ZEND_TYPE_IS_SET(parent_info->type)) {
1550
176
        inheritance_status status = verify_property_type_compatibility(
1551
176
          parent_info, child_info, variance, true, false);
1552
176
        if (status == INHERITANCE_UNRESOLVED) {
1553
4
          add_property_compatibility_obligation(ce, child_info, parent_info, variance);
1554
4
        }
1555
187
      } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1556
2
        zend_error_noreturn(E_COMPILE_ERROR,
1557
2
            "Type of %s::$%s must be omitted to match the parent definition in class %s",
1558
2
            ZSTR_VAL(ce->name),
1559
2
            ZSTR_VAL(key),
1560
2
            ZSTR_VAL(parent_info->ce->name));
1561
2
      }
1562
1563
361
      if (child_info->ce == ce) {
1564
335
        child_info->flags &= ~ZEND_ACC_OVERRIDE;
1565
335
      }
1566
361
    }
1567
2.11k
  } else {
1568
2.11k
    zend_function **hooks = parent_info->hooks;
1569
2.11k
    if (hooks) {
1570
79
      ce->num_hooked_props++;
1571
79
      if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1572
0
        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1573
0
      }
1574
79
    }
1575
1576
2.11k
    _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1577
2.11k
  }
1578
2.60k
}
1579
/* }}} */
1580
1581
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1582
2.68k
{
1583
2.68k
  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.68k
  ZEND_ASSERT(ce != iface);
1588
2.68k
}
1589
/* }}} */
1590
1591
static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1592
690
{
1593
  /* expects interface to be contained in ce's interface list already */
1594
690
  uint32_t i, ce_num, if_num = iface->num_interfaces;
1595
1596
690
  ce_num = ce->num_interfaces;
1597
1598
690
  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
1.83k
  while (if_num--) {
1602
1.14k
    zend_class_entry *entry = iface->interfaces[if_num];
1603
1.45k
    for (i = 0; i < ce_num; i++) {
1604
536
      if (ce->interfaces[i] == entry) {
1605
222
        break;
1606
222
      }
1607
536
    }
1608
1.14k
    if (i == ce_num) {
1609
922
      ce->interfaces[ce->num_interfaces++] = entry;
1610
922
    }
1611
1.14k
  }
1612
690
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1613
1614
  /* and now call the implementing handlers */
1615
1.61k
  while (ce_num < ce->num_interfaces) {
1616
922
    do_implement_interface(ce, ce->interfaces[ce_num++]);
1617
922
  }
1618
690
}
1619
/* }}} */
1620
1621
static void emit_incompatible_class_constant_error(
1622
0
    const zend_class_constant *child, const zend_class_constant *parent, const zend_string *const_name) {
1623
0
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1624
0
  zend_error_noreturn(E_COMPILE_ERROR,
1625
0
    "Type of %s::%s must be compatible with %s::%s of type %s",
1626
0
    ZSTR_VAL(child->ce->name),
1627
0
    ZSTR_VAL(const_name),
1628
0
    ZSTR_VAL(parent->ce->name),
1629
0
    ZSTR_VAL(const_name),
1630
0
    ZSTR_VAL(type_str));
1631
0
}
1632
1633
static inheritance_status class_constant_types_compatible(const zend_class_constant *parent, const zend_class_constant *child)
1634
48
{
1635
48
  ZEND_ASSERT(ZEND_TYPE_IS_SET(parent->type));
1636
1637
48
  if (!ZEND_TYPE_IS_SET(child->type)) {
1638
0
    return INHERITANCE_ERROR;
1639
0
  }
1640
1641
48
  return zend_perform_covariant_type_check(child->ce, child->type, parent->ce, parent->type);
1642
48
}
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
816
{
1649
816
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1650
816
  zend_class_constant *c;
1651
1652
816
  if (zv != NULL) {
1653
98
    c = (zend_class_constant*)Z_PTR_P(zv);
1654
98
    bool inherit = do_inherit_constant_check(ce, parent_const, name);
1655
98
    ZEND_ASSERT(!inherit);
1656
718
  } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1657
714
    if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1658
42
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1659
42
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1660
42
      if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
1661
12
        c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1662
12
        memcpy(c, parent_const, sizeof(zend_class_constant));
1663
12
        parent_const = c;
1664
12
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1665
12
      }
1666
42
    }
1667
714
    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
714
    _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1673
714
  }
1674
816
}
1675
/* }}} */
1676
1677
void zend_build_properties_info_table(zend_class_entry *ce)
1678
11.1k
{
1679
11.1k
  zend_property_info **table, *prop;
1680
11.1k
  size_t size;
1681
11.1k
  if (ce->default_properties_count == 0) {
1682
6.80k
    return;
1683
6.80k
  }
1684
1685
4.36k
  ZEND_ASSERT(ce->properties_info_table == NULL);
1686
4.36k
  size = sizeof(zend_property_info *) * ce->default_properties_count;
1687
4.36k
  if (ce->type == ZEND_USER_CLASS) {
1688
4.25k
    ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1689
4.25k
  } 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
4.36k
  memset(table, 0, size);
1695
1696
4.36k
  if (ce->parent && ce->parent->default_properties_count != 0) {
1697
730
    zend_property_info **parent_table = ce->parent->properties_info_table;
1698
730
    memcpy(
1699
730
      table, parent_table,
1700
730
      sizeof(zend_property_info *) * ce->parent->default_properties_count
1701
730
    );
1702
1703
    /* Child did not add any new properties, we are done */
1704
730
    if (ce->default_properties_count == ce->parent->default_properties_count) {
1705
467
      return;
1706
467
    }
1707
730
  }
1708
1709
21.4k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, prop) {
1710
21.4k
    if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0
1711
6.05k
     && !(prop->flags & ZEND_ACC_VIRTUAL)) {
1712
5.89k
      const zend_property_info *root_prop = prop->prototype;
1713
5.89k
      if (UNEXPECTED(root_prop->flags & ZEND_ACC_VIRTUAL)) {
1714
        /* Prototype is virtual, we need to manually hunt down the first backed property. */
1715
30
        root_prop = prop;
1716
30
        zend_class_entry *parent_ce;
1717
36
        while ((parent_ce = root_prop->ce->parent)) {
1718
36
          zend_property_info *parent_prop = zend_hash_find_ptr(&parent_ce->properties_info, key);
1719
36
          if (!parent_prop
1720
36
           || parent_prop->prototype != prop->prototype
1721
36
           || (parent_prop->flags & ZEND_ACC_VIRTUAL)) {
1722
30
            break;
1723
30
          }
1724
6
          root_prop = parent_prop;
1725
6
        }
1726
30
      }
1727
5.89k
      uint32_t prop_table_offset = OBJ_PROP_TO_NUM(root_prop->offset);
1728
5.89k
      table[prop_table_offset] = prop;
1729
5.89k
    }
1730
21.4k
  } ZEND_HASH_FOREACH_END();
1731
3.89k
}
1732
1733
ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name)
1734
760
{
1735
760
  if (!prop_info->hooks) {
1736
0
    return;
1737
0
  }
1738
760
  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
760
  if ((prop_info->flags & ZEND_ACC_VIRTUAL) && prop_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1742
2
    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
2
    } else {
1745
2
      zend_error_noreturn(E_COMPILE_ERROR,
1746
2
        "Cannot specify default value for virtual hooked property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1747
2
    }
1748
2
  }
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
758
  if (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1752
363
   && !ZEND_TYPE_IS_SET(prop_info->type)
1753
225
   && Z_TYPE(ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]) == IS_UNDEF) {
1754
112
    ZVAL_NULL(&ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]);
1755
112
  }
1756
2.27k
  for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1757
1.51k
    const zend_function *func = prop_info->hooks[i];
1758
1.51k
    if (func) {
1759
988
      if ((zend_property_hook_kind)i == ZEND_PROPERTY_HOOK_GET
1760
592
       && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1761
40
       && !(prop_info->flags & ZEND_ACC_VIRTUAL)
1762
8
       && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1763
2
        zend_error_noreturn(E_COMPILE_ERROR, "Get hook of backed property %s::%s with set hook may not return by reference",
1764
2
          ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1765
2
      }
1766
986
      if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
1767
72
        abstract_error = false;
1768
72
      }
1769
986
    }
1770
1.51k
  }
1771
756
  if (abstract_error) {
1772
0
    zend_error_noreturn(E_COMPILE_ERROR,
1773
0
      "Abstract property %s::$%s must specify at least one abstract hook", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1774
0
  }
1775
756
  if ((prop_info->flags & ZEND_ACC_VIRTUAL)
1776
395
   && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)
1777
18
   && (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET] || !prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1778
0
    const char *prefix = !prop_info->hooks[ZEND_PROPERTY_HOOK_GET]
1779
0
      ? "set-only" : "get-only";
1780
0
    zend_error_noreturn(E_COMPILE_ERROR,
1781
0
      "%s virtual property %s::$%s must not specify asymmetric visibility",
1782
0
      prefix, ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1783
0
  }
1784
756
}
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
0
{
1788
0
  zend_error_noreturn(E_COMPILE_ERROR, "Type of parameter $%s of hook %s::$%s::set must be compatible with property type",
1789
0
    ZSTR_VAL(value_param_name), ZSTR_VAL(class_name), zend_get_unmangled_property_name(prop_name));
1790
0
}
1791
1792
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info)
1793
0
{
1794
0
  zend_string *value_param_name = prop_info->hooks[ZEND_PROPERTY_HOOK_SET]->op_array.arg_info[0].name;
1795
0
  zend_hooked_property_variance_error_ex(value_param_name, prop_info->ce->name, prop_info->name);
1796
0
}
1797
1798
ZEND_API inheritance_status zend_verify_property_hook_variance(const zend_property_info *prop_info, const zend_function *func)
1799
394
{
1800
394
  ZEND_ASSERT(prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET] == func);
1801
1802
394
  zend_arg_info *value_arg_info = &func->op_array.arg_info[0];
1803
394
  if (!ZEND_TYPE_IS_SET(value_arg_info->type)) {
1804
242
    return INHERITANCE_SUCCESS;
1805
242
  }
1806
1807
152
  if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1808
0
    return INHERITANCE_ERROR;
1809
0
  }
1810
1811
152
  zend_class_entry *ce = prop_info->ce;
1812
152
  return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type);
1813
152
}
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.09k
{
1838
2.09k
  zend_property_info *property_info;
1839
2.09k
  zend_string *key;
1840
1841
2.09k
  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.09k
  } 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
0
    if (parent_ce->ce_flags & ZEND_ACC_ENUM) {
1850
0
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend enum %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1851
0
    }
1852
    /* Class must not extend a final class */
1853
0
    if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1854
0
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1855
0
    }
1856
1857
    /* Class declaration must not extend traits or interfaces */
1858
0
    if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1859
0
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1860
0
        ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1861
0
      );
1862
0
    }
1863
0
  }
1864
1865
2.09k
  if (UNEXPECTED((ce->ce_flags & ZEND_ACC_READONLY_CLASS) != (parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS))) {
1866
0
    zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1867
0
      ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1868
0
      parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1869
0
    );
1870
0
  }
1871
1872
2.09k
  if (ce->parent_name) {
1873
1.94k
    zend_string_release_ex(ce->parent_name, 0);
1874
1.94k
  }
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
748
    zval *src, *dst, *end;
1882
1883
748
    if (ce->default_properties_count) {
1884
253
      zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1885
253
      src = ce->default_properties_table + ce->default_properties_count;
1886
253
      end = table + parent_ce->default_properties_count;
1887
253
      dst = end + ce->default_properties_count;
1888
253
      ce->default_properties_table = table;
1889
369
      do {
1890
369
        dst--;
1891
369
        src--;
1892
369
        ZVAL_COPY_VALUE_PROP(dst, src);
1893
369
      } while (dst != end);
1894
253
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1895
253
      end = ce->default_properties_table;
1896
495
    } else {
1897
495
      end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1898
495
      dst = end + parent_ce->default_properties_count;
1899
495
      ce->default_properties_table = end;
1900
495
    }
1901
748
    src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1902
748
    if (UNEXPECTED(parent_ce->type != ce->type)) {
1903
      /* User class extends internal */
1904
688
      do {
1905
688
        dst--;
1906
688
        src--;
1907
        /* We don't have to account for refcounting because
1908
         * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1909
688
        ZEND_ASSERT(!Z_REFCOUNTED_P(src));
1910
688
        ZVAL_COPY_VALUE_PROP(dst, src);
1911
688
        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
688
        continue;
1916
688
      } while (dst != end);
1917
618
    } else {
1918
1.46k
      do {
1919
1.46k
        dst--;
1920
1.46k
        src--;
1921
1.46k
        ZVAL_COPY_PROP(dst, src);
1922
1.46k
        if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1923
8
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1924
8
          ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1925
8
        }
1926
1.46k
        continue;
1927
1.46k
      } while (dst != end);
1928
618
    }
1929
748
    ce->default_properties_count += parent_ce->default_properties_count;
1930
748
  }
1931
1932
2.09k
  if (parent_ce->default_static_members_count) {
1933
106
    zval *src, *dst, *end;
1934
1935
106
    if (ce->default_static_members_count) {
1936
42
      zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1937
42
      src = ce->default_static_members_table + ce->default_static_members_count;
1938
42
      end = table + parent_ce->default_static_members_count;
1939
42
      dst = end + ce->default_static_members_count;
1940
42
      ce->default_static_members_table = table;
1941
78
      do {
1942
78
        dst--;
1943
78
        src--;
1944
78
        ZVAL_COPY_VALUE(dst, src);
1945
78
      } while (dst != end);
1946
42
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1947
42
      end = ce->default_static_members_table;
1948
64
    } else {
1949
64
      end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1950
64
      dst = end + parent_ce->default_static_members_count;
1951
64
      ce->default_static_members_table = end;
1952
64
    }
1953
106
    src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1954
188
    do {
1955
188
      dst--;
1956
188
      src--;
1957
188
      if (Z_TYPE_P(src) == IS_INDIRECT) {
1958
8
        ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1959
180
      } else {
1960
180
        ZVAL_INDIRECT(dst, src);
1961
180
      }
1962
188
      if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1963
2
        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1964
2
        ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
1965
2
      }
1966
188
    } while (dst != end);
1967
106
    ce->default_static_members_count += parent_ce->default_static_members_count;
1968
106
    if (!ZEND_MAP_PTR(ce->static_members_table)) {
1969
106
      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
106
    }
1974
106
  }
1975
1976
5.76k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1977
5.76k
    if (property_info->ce == ce) {
1978
783
      if (property_info->flags & ZEND_ACC_STATIC) {
1979
134
        property_info->offset += parent_ce->default_static_members_count;
1980
649
      } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1981
513
        property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1982
513
      }
1983
783
    }
1984
5.76k
  } ZEND_HASH_FOREACH_END();
1985
1986
2.09k
  if (zend_hash_num_elements(&parent_ce->properties_info)) {
1987
918
    zend_hash_extend(&ce->properties_info,
1988
918
      zend_hash_num_elements(&ce->properties_info) +
1989
918
      zend_hash_num_elements(&parent_ce->properties_info), 0);
1990
1991
7.00k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1992
7.00k
      do_inherit_property(property_info, key, ce);
1993
7.00k
    } ZEND_HASH_FOREACH_END();
1994
918
  }
1995
1996
2.09k
  if (ce->num_hooked_props) {
1997
1.32k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
1998
1.32k
      if (property_info->ce == ce && property_info->hooks) {
1999
207
        zend_verify_hooked_property(ce, property_info, key);
2000
207
      }
2001
1.32k
    } ZEND_HASH_FOREACH_END();
2002
177
  }
2003
2004
2.09k
  if (zend_hash_num_elements(&parent_ce->constants_table)) {
2005
231
    zend_class_constant *c;
2006
2007
231
    zend_hash_extend(&ce->constants_table,
2008
231
      zend_hash_num_elements(&ce->constants_table) +
2009
231
      zend_hash_num_elements(&parent_ce->constants_table), 0);
2010
2011
2.09k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
2012
2.09k
      do_inherit_class_constant(key, c, ce);
2013
2.09k
    } ZEND_HASH_FOREACH_END();
2014
231
  }
2015
2016
2.09k
  if (zend_hash_num_elements(&parent_ce->function_table)) {
2017
1.53k
    zend_hash_extend(&ce->function_table,
2018
1.53k
      zend_hash_num_elements(&ce->function_table) +
2019
1.53k
      zend_hash_num_elements(&parent_ce->function_table), 0);
2020
1.53k
    uint32_t flags =
2021
1.53k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2022
1.53k
      ZEND_INHERITANCE_SET_CHILD_CHANGED |
2023
1.53k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2024
1.53k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2025
2026
1.53k
    if (!checked) {
2027
530
      flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2028
530
    }
2029
1.53k
    zend_function *func;
2030
16.7k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
2031
16.7k
      do_inherit_method(key, func, ce, false, flags);
2032
16.7k
    } ZEND_HASH_FOREACH_END();
2033
1.53k
  }
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
58
{
2052
58
  bool is_compatible;
2053
58
  zval op1_tmp, op2_tmp;
2054
2055
  /* if any of the values is a constant, we try to resolve it */
2056
58
  if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
2057
14
    ZVAL_COPY_OR_DUP(&op1_tmp, op1);
2058
14
    if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
2059
4
      zval_ptr_dtor(&op1_tmp);
2060
4
      return false;
2061
4
    }
2062
10
    op1 = &op1_tmp;
2063
10
  }
2064
54
  if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
2065
10
    ZVAL_COPY_OR_DUP(&op2_tmp, op2);
2066
10
    if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
2067
0
      zval_ptr_dtor(&op2_tmp);
2068
0
      return false;
2069
0
    }
2070
10
    op2 = &op2_tmp;
2071
10
  }
2072
2073
54
  is_compatible = fast_is_identical_function(op1, op2);
2074
2075
54
  if (op1 == &op1_tmp) {
2076
10
    zval_ptr_dtor_nogc(&op1_tmp);
2077
10
  }
2078
54
  if (op2 == &op2_tmp) {
2079
10
    zval_ptr_dtor_nogc(&op2_tmp);
2080
10
  }
2081
2082
54
  return is_compatible;
2083
54
}
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
242
) {
2090
242
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2091
242
  if (zv == NULL) {
2092
122
    return true;
2093
122
  }
2094
2095
120
  zend_class_constant *child_constant = Z_PTR_P(zv);
2096
120
  if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
2097
0
    zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
2098
0
      ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2099
0
      ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
2100
0
    );
2101
0
  }
2102
2103
120
  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
120
  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
120
  if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
2123
38
    inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
2124
38
    if (status == INHERITANCE_ERROR) {
2125
0
      emit_incompatible_class_constant_error(child_constant, parent_constant, name);
2126
38
    } else if (status == INHERITANCE_UNRESOLVED) {
2127
0
      add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
2128
0
    }
2129
38
  }
2130
2131
120
  return false;
2132
120
}
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
136
{
2137
136
  if (do_inherit_constant_check(ce, c, name)) {
2138
122
    zend_class_constant *ct;
2139
122
    if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2140
8
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2141
8
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2142
8
      if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
2143
8
        ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2144
8
        memcpy(ct, c, sizeof(zend_class_constant));
2145
8
        c = ct;
2146
8
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2147
8
      }
2148
8
    }
2149
122
    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
122
    zend_hash_update_ptr(&ce->constants_table, name, c);
2155
122
  }
2156
136
}
2157
/* }}} */
2158
2159
static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2160
1.73k
{
2161
1.73k
  zend_function *func;
2162
1.73k
  zend_string *key;
2163
1.73k
  zend_class_constant *c;
2164
1.73k
  uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2165
2166
1.73k
  if (iface->num_interfaces) {
2167
368
    zend_do_inherit_interfaces(ce, iface);
2168
368
  }
2169
2170
1.73k
  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
1.63k
    flags |=
2174
1.63k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2175
1.63k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2176
1.63k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2177
1.63k
  } else {
2178
104
    flags |=
2179
104
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2180
104
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2181
104
  }
2182
2183
3.74k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2184
3.74k
    do_inherit_iface_constant(key, c, ce, iface);
2185
3.74k
  } ZEND_HASH_FOREACH_END();
2186
2187
8.84k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2188
8.84k
    do_inherit_method(key, func, ce, true, flags);
2189
8.84k
  } ZEND_HASH_FOREACH_END();
2190
2191
1.73k
  zend_hash_extend(&ce->properties_info,
2192
1.73k
    zend_hash_num_elements(&ce->properties_info) +
2193
1.73k
    zend_hash_num_elements(&iface->properties_info), 0);
2194
2195
1.73k
  zend_property_info *prop;
2196
1.77k
  ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2197
1.77k
    do_inherit_property(prop, key, ce);
2198
1.77k
  } ZEND_HASH_FOREACH_END();
2199
2200
1.73k
  do_implement_interface(ce, iface);
2201
1.73k
}
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
1.24k
{
2244
1.24k
  uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2245
1.24k
  uint32_t num_interfaces = num_parent_interfaces;
2246
1.24k
  zend_string *key;
2247
1.24k
  zend_class_constant *c;
2248
1.24k
  uint32_t i;
2249
2250
2.79k
  for (i = 0; i < ce->num_interfaces; i++) {
2251
1.54k
    zend_class_entry *iface = interfaces[num_parent_interfaces + i];
2252
1.54k
    if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2253
0
      add_dependency_obligation(ce, iface);
2254
0
    }
2255
1.54k
    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
1.89k
    for (uint32_t j = 0; j < num_interfaces; j++) {
2260
372
      if (interfaces[j] == iface) {
2261
22
        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
60
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2270
60
          do_inherit_constant_check(ce, c, key);
2271
60
        } ZEND_HASH_FOREACH_END();
2272
2273
22
        iface = NULL;
2274
22
        break;
2275
22
      }
2276
372
    }
2277
1.54k
    if (iface) {
2278
1.52k
      interfaces[num_interfaces] = iface;
2279
1.52k
      num_interfaces++;
2280
1.52k
    }
2281
1.54k
  }
2282
2283
1.24k
  if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2284
24
    for (i = 0; i < ce->num_interfaces; i++) {
2285
12
      zend_string_release_ex(ce->interface_names[i].name, 0);
2286
12
      zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2287
12
    }
2288
12
    efree(ce->interface_names);
2289
12
  }
2290
2291
1.24k
  ce->num_interfaces = num_interfaces;
2292
1.24k
  ce->interfaces = interfaces;
2293
1.24k
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2294
2295
1.30k
  for (i = 0; i < num_parent_interfaces; i++) {
2296
58
    do_implement_interface(ce, ce->interfaces[i]);
2297
58
  }
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
2.77k
  for (; i < num_interfaces; i++) {
2301
1.52k
    do_interface_implementation(ce, ce->interfaces[i]);
2302
1.52k
  }
2303
1.24k
}
2304
/* }}} */
2305
2306
2307
void zend_inheritance_check_override(const zend_class_entry *ce)
2308
10.9k
{
2309
10.9k
  if (ce->ce_flags & ZEND_ACC_TRAIT) {
2310
620
    return;
2311
620
  }
2312
2313
49.7k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *f) {
2314
49.7k
    if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2315
0
      ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2316
2317
0
      zend_error_at_noreturn(
2318
0
        E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2319
0
        "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2320
0
        ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2321
0
    }
2322
49.7k
  } ZEND_HASH_FOREACH_END();
2323
2324
38.4k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
2325
38.4k
    if (prop->flags & ZEND_ACC_OVERRIDE) {
2326
2
      zend_error_noreturn(
2327
2
        E_COMPILE_ERROR,
2328
2
        "%s::$%s has #[\\Override] attribute, but no matching parent property exists",
2329
2
        ZSTR_VAL(ce->name), zend_get_unmangled_property_name(prop->name));
2330
2
    }
2331
2332
8.89k
    if (prop->hooks) {
2333
2.46k
      for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2334
1.64k
        zend_function *f = prop->hooks[i];
2335
1.64k
        if (f && f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2336
4
          ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2337
2338
4
          zend_error_at_noreturn(
2339
4
            E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2340
4
            "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2341
4
            ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2342
4
        }
2343
1.64k
      }
2344
823
    }
2345
8.89k
  } ZEND_HASH_FOREACH_END();
2346
10.3k
}
2347
2348
2349
static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
2350
184
{
2351
  /* self in trait methods should be resolved to the using class, not the trait. */
2352
184
  return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
2353
184
}
2354
2355
static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
2356
790
{
2357
790
  zend_function *existing_fn = NULL;
2358
790
  zend_function *new_fn;
2359
2360
790
  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
136
    if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
2364
2
      (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
2365
2
      (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2366
2
      return;
2367
2
    }
2368
2369
    /* Abstract method signatures from the trait must be satisfied. */
2370
134
    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
92
      do_inheritance_check_on_method(
2377
92
        existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
2378
92
        ce, NULL, ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
2379
92
      return;
2380
92
    }
2381
2382
42
    if (existing_fn->common.scope == ce) {
2383
      /* members from the current class override trait methods */
2384
32
      return;
2385
32
    } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
2386
10
        && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
2387
      /* two traits can't define the same non-abstract method */
2388
10
      zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
2389
10
        ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
2390
10
        ZSTR_VAL(ce->name), ZSTR_VAL(name),
2391
10
        ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
2392
10
    }
2393
42
  }
2394
2395
654
  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
654
  } else {
2400
654
    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2401
654
    memcpy(new_fn, fn, sizeof(zend_op_array));
2402
654
    new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2403
654
  }
2404
654
  new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2405
2406
  /* Reassign method name, in case it is an alias. */
2407
654
  new_fn->common.function_name = name;
2408
654
  function_add_ref(new_fn);
2409
654
  fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2410
654
  zend_add_magic_method(ce, fn, key);
2411
654
}
2412
/* }}} */
2413
2414
static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2415
916
{
2416
916
  if (fn->common.scope->ce_flags & ZEND_ACC_TRAIT) {
2417
2418
652
    fn->common.scope = ce;
2419
2420
652
    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2421
6
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2422
6
    }
2423
652
    if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2424
30
      ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2425
30
    }
2426
652
  }
2427
916
}
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
790
{
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
790
  if (!(original_fn_flags & ZEND_ACC_FINAL)
2437
754
    && (fn_copy->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2438
6
    && !zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2439
6
    zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2440
6
  }
2441
790
}
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
720
{
2445
720
  zend_trait_alias  *alias, **alias_ptr;
2446
720
  zend_function      fn_copy;
2447
720
  int                i;
2448
2449
  /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2450
720
  if (ce->trait_aliases) {
2451
148
    alias_ptr = ce->trait_aliases;
2452
148
    alias = *alias_ptr;
2453
148
    i = 0;
2454
662
    while (alias) {
2455
      /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2456
514
      if (alias->alias != NULL
2457
274
        && fn->common.scope == aliases[i]
2458
150
        && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2459
514
      ) {
2460
94
        fn_copy = *fn;
2461
94
        if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2462
16
          fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2463
78
        } else {
2464
78
          fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2465
78
        }
2466
2467
94
        zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2468
2469
94
        zend_string *lcname = zend_string_tolower(alias->alias);
2470
94
        zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2471
94
        zend_string_release_ex(lcname, 0);
2472
94
      }
2473
514
      alias_ptr++;
2474
514
      alias = *alias_ptr;
2475
514
      i++;
2476
514
    }
2477
148
  }
2478
2479
720
  if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2480
    /* is not in hashtable, thus, function is not to be excluded */
2481
696
    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
696
    if (ce->trait_aliases) {
2485
140
      alias_ptr = ce->trait_aliases;
2486
140
      alias = *alias_ptr;
2487
140
      i = 0;
2488
632
      while (alias) {
2489
        /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2490
492
        if (alias->alias == NULL && alias->modifiers != 0
2491
236
          && fn->common.scope == aliases[i]
2492
218
          && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2493
492
        ) {
2494
52
          if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2495
30
            fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2496
30
          } else {
2497
22
            fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2498
22
          }
2499
52
        }
2500
492
        alias_ptr++;
2501
492
        alias = *alias_ptr;
2502
492
        i++;
2503
492
      }
2504
140
    }
2505
2506
696
    zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2507
2508
696
    zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2509
696
  }
2510
720
}
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
136
{
2515
136
  if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2516
4
    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
4
  }
2518
2519
196
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2520
190
    if (traits[i] == trait) {
2521
126
      return i;
2522
126
    }
2523
190
  }
2524
6
  zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
2525
132
}
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
568
{
2530
568
  size_t i, j = 0;
2531
568
  zend_trait_precedence *cur_precedence;
2532
568
  zend_trait_method_reference *cur_method_ref;
2533
568
  zend_string *lc_trait_name;
2534
568
  zend_string *lcname;
2535
568
  HashTable **exclude_tables = NULL;
2536
568
  zend_class_entry **aliases = NULL;
2537
568
  zend_class_entry *trait;
2538
2539
  /* resolve class references */
2540
568
  if (ce->trait_precedences) {
2541
30
    exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2542
30
    i = 0;
2543
30
    zend_trait_precedence **precedences = ce->trait_precedences;
2544
30
    ce->trait_precedences = NULL;
2545
62
    while ((cur_precedence = precedences[i])) {
2546
      /** Resolve classes for all precedence operations. */
2547
38
      cur_method_ref = &cur_precedence->trait_method;
2548
38
      lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2549
38
      trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2550
38
      zend_string_release_ex(lc_trait_name, 0);
2551
38
      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
38
      zend_check_trait_usage(ce, trait, traits);
2555
2556
      /** Ensure that the preferred method is actually available. */
2557
38
      lcname = zend_string_tolower(cur_method_ref->method_name);
2558
38
      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
68
      for (j = 0; j < cur_precedence->num_excludes; j++) {
2573
36
        zend_string* class_name = cur_precedence->exclude_class_names[j];
2574
36
        zend_class_entry *exclude_ce;
2575
36
        uint32_t trait_num;
2576
2577
36
        lc_trait_name = zend_string_tolower(class_name);
2578
36
        exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2579
36
        zend_string_release_ex(lc_trait_name, 0);
2580
36
        if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2581
2
          zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2582
2
        }
2583
34
        trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2584
34
        if (!exclude_tables[trait_num]) {
2585
26
          ALLOC_HASHTABLE(exclude_tables[trait_num]);
2586
26
          zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2587
26
        }
2588
34
        if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2589
2
          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
2
        }
2591
2592
        /* make sure that the trait method is not from a class mentioned in
2593
         exclude_from_classes, for consistency */
2594
32
        if (trait == exclude_ce) {
2595
2
          zend_error_noreturn(E_COMPILE_ERROR,
2596
2
                 "Inconsistent insteadof definition. "
2597
2
                 "The method %s is to be used from %s, but %s is also on the exclude list",
2598
2
                 ZSTR_VAL(cur_method_ref->method_name),
2599
2
                 ZSTR_VAL(trait->name),
2600
2
                 ZSTR_VAL(trait->name));
2601
2
        }
2602
32
      }
2603
32
      zend_string_release_ex(lcname, 0);
2604
32
      i++;
2605
32
    }
2606
24
    ce->trait_precedences = precedences;
2607
24
  }
2608
2609
562
  if (ce->trait_aliases) {
2610
86
    i = 0;
2611
246
    while (ce->trait_aliases[i]) {
2612
160
      i++;
2613
160
    }
2614
86
    aliases = ecalloc(i, sizeof(zend_class_entry*));
2615
86
    i = 0;
2616
240
    while (ce->trait_aliases[i]) {
2617
160
      const zend_trait_alias *cur_alias = ce->trait_aliases[i];
2618
160
      cur_method_ref = &ce->trait_aliases[i]->trait_method;
2619
160
      lcname = zend_string_tolower(cur_method_ref->method_name);
2620
160
      if (cur_method_ref->class_name) {
2621
        /* For all aliases with an explicit class name, resolve the class now. */
2622
64
        lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2623
64
        trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2624
64
        zend_string_release_ex(lc_trait_name, 0);
2625
64
        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
64
        zend_check_trait_usage(ce, trait, traits);
2629
64
        aliases[i] = trait;
2630
2631
        /* And, ensure that the referenced method is resolvable, too. */
2632
64
        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
96
      } else {
2636
        /* Find out which trait this method refers to. */
2637
96
        trait = NULL;
2638
224
        for (j = 0; j < ce->num_traits; j++) {
2639
130
          if (traits[j]) {
2640
128
            if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2641
94
              if (!trait) {
2642
92
                trait = traits[j];
2643
92
                continue;
2644
92
              }
2645
2646
2
              zend_error_noreturn(E_COMPILE_ERROR,
2647
2
                "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
2
                ZSTR_VAL(cur_method_ref->method_name),
2649
2
                ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2650
2
                ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2651
2
                ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2652
94
            }
2653
128
          }
2654
130
        }
2655
2656
        /* Non-absolute method reference refers to method that does not exist. */
2657
94
        if (!trait) {
2658
4
          if (cur_alias->alias) {
2659
2
            zend_error_noreturn(E_COMPILE_ERROR,
2660
2
              "An alias (%s) was defined for method %s(), but this method does not exist",
2661
2
              ZSTR_VAL(cur_alias->alias),
2662
2
              ZSTR_VAL(cur_alias->trait_method.method_name));
2663
2
          } else {
2664
2
            zend_error_noreturn(E_COMPILE_ERROR,
2665
2
              "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2666
2
              ZSTR_VAL(cur_alias->trait_method.method_name));
2667
2
          }
2668
4
        }
2669
2670
90
        aliases[i] = trait;
2671
90
      }
2672
154
      zend_string_release_ex(lcname, 0);
2673
154
      i++;
2674
154
    }
2675
86
  }
2676
2677
556
  *exclude_tables_ptr = exclude_tables;
2678
556
  *aliases_ptr = aliases;
2679
556
}
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
614
{
2684
614
  uint32_t i;
2685
614
  zend_string *key;
2686
614
  zend_function *fn;
2687
2688
614
  if (exclude_tables) {
2689
58
    for (i = 0; i < ce->num_traits; i++) {
2690
40
      if (traits[i]) {
2691
        /* copies functions, applies defined aliasing, and excludes unused trait methods */
2692
216
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2693
216
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2694
216
          *contains_abstract_methods |= is_abstract;
2695
216
          if (verify_abstract != is_abstract) {
2696
0
            continue;
2697
0
          }
2698
68
          zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2699
68
        } ZEND_HASH_FOREACH_END();
2700
2701
40
        if (exclude_tables[i]) {
2702
22
          zend_hash_destroy(exclude_tables[i]);
2703
22
          FREE_HASHTABLE(exclude_tables[i]);
2704
22
          exclude_tables[i] = NULL;
2705
22
        }
2706
40
      }
2707
40
    }
2708
596
  } else {
2709
1.33k
    for (i = 0; i < ce->num_traits; i++) {
2710
734
      if (traits[i]) {
2711
3.09k
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2712
3.09k
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2713
3.09k
          *contains_abstract_methods |= is_abstract;
2714
3.09k
          if (verify_abstract != is_abstract) {
2715
162
            continue;
2716
162
          }
2717
652
          zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2718
652
        } ZEND_HASH_FOREACH_END();
2719
732
      }
2720
734
    }
2721
596
  }
2722
614
}
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
8
{
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
8
  if (colliding_ce == ce) {
2735
8
    for (size_t i = 0; i < current_trait; i++) {
2736
2
      if (traits[i]
2737
2
        && zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2738
2
        return traits[i];
2739
2
      }
2740
2
    }
2741
8
  }
2742
  /* Traits don't have it, then the composing class (or trait) itself has it. */
2743
6
  return colliding_ce;
2744
8
}
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
8
) {
2751
8
  zend_error_noreturn(E_COMPILE_ERROR,
2752
8
    "%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
8
    ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2754
8
    ZSTR_VAL(trait_constant->ce->name),
2755
8
    ZSTR_VAL(name),
2756
8
    ZSTR_VAL(ce->name)
2757
8
  );
2758
8
}
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
80
) {
2776
80
  uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2777
2778
80
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2779
80
  if (zv == NULL) {
2780
    /* No existing constant of the same name, so this one can be added */
2781
46
    return true;
2782
46
  }
2783
2784
34
  zend_class_constant *existing_constant = Z_PTR_P(zv);
2785
2786
34
  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
34
  if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2792
4
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2793
4
    return false;
2794
4
  }
2795
2796
30
  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
30
  } else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2800
18
    inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2801
18
    inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2802
18
    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
18
  }
2807
2808
30
  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
4
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2811
4
    return false;
2812
4
  }
2813
2814
  /* There is an existing constant which is compatible with the new one, so no need to add it */
2815
26
  return false;
2816
30
}
2817
2818
static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2819
536
{
2820
1.18k
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2821
648
    zend_string *constant_name;
2822
648
    zend_class_constant *constant;
2823
2824
648
    if (!traits[i]) {
2825
2
      continue;
2826
2
    }
2827
2828
1.45k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2829
1.45k
      if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2830
46
        zend_class_constant *ct = NULL;
2831
2832
46
        ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2833
46
        memcpy(ct, constant, sizeof(zend_class_constant));
2834
46
        constant = ct;
2835
2836
46
        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
46
        constant->ce = ce;
2846
2847
46
        Z_TRY_ADDREF(constant->value);
2848
46
        constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2849
46
        if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2850
0
          GC_ADDREF(constant->attributes);
2851
0
        }
2852
2853
46
        zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2854
46
      }
2855
1.45k
    } ZEND_HASH_FOREACH_END();
2856
646
  }
2857
536
}
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
8
{
2862
8
  if (colliding_ce == ce) {
2863
8
    for (size_t i = 0; i < current_trait; i++) {
2864
2
      if (traits[i]
2865
2
       && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2866
2
        return traits[i];
2867
2
      }
2868
2
    }
2869
8
  }
2870
2871
6
  return colliding_ce;
2872
8
}
2873
/* }}} */
2874
2875
static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2876
528
{
2877
528
  zend_property_info *property_info;
2878
528
  const zend_property_info *colliding_prop;
2879
528
  zend_string* prop_name;
2880
528
  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
1.15k
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2888
638
    if (!traits[i]) {
2889
2
      continue;
2890
2
    }
2891
1.59k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2892
1.59k
      uint32_t flags = property_info->flags;
2893
2894
      /* next: check for conflicts with current class */
2895
1.59k
      if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2896
34
        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
34
        } else {
2900
34
          bool is_compatible = false;
2901
34
          uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2902
2903
34
          if (colliding_prop->hooks || property_info->hooks) {
2904
2
            zend_error_noreturn(E_COMPILE_ERROR,
2905
2
              "%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
2
              ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2907
2
              ZSTR_VAL(property_info->ce->name),
2908
2
              ZSTR_VAL(prop_name),
2909
2
              ZSTR_VAL(ce->name));
2910
2
          }
2911
2912
32
          if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2913
28
            verify_property_type_compatibility(property_info, colliding_prop, PROP_INVARIANT, false, false) == INHERITANCE_SUCCESS
2914
32
          ) {
2915
            /* the flags are identical, thus, the properties may be compatible */
2916
28
            zval *op1, *op2;
2917
2918
28
            if (flags & ZEND_ACC_STATIC) {
2919
8
              op1 = &ce->default_static_members_table[colliding_prop->offset];
2920
8
              op2 = &traits[i]->default_static_members_table[property_info->offset];
2921
8
              ZVAL_DEINDIRECT(op1);
2922
8
              ZVAL_DEINDIRECT(op2);
2923
20
            } else {
2924
20
              op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2925
20
              op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2926
20
            }
2927
28
            is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2928
28
          }
2929
2930
32
          if (!is_compatible) {
2931
6
            zend_error_noreturn(E_COMPILE_ERROR,
2932
6
                "%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
6
                ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2934
6
                ZSTR_VAL(property_info->ce->name),
2935
6
                ZSTR_VAL(prop_name),
2936
6
                ZSTR_VAL(ce->name));
2937
6
          }
2938
26
          continue;
2939
32
        }
2940
34
      }
2941
2942
126
      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
126
      zval tmp_prop_value;
2953
126
      if (!(flags & ZEND_ACC_VIRTUAL)) {
2954
118
        if (flags & ZEND_ACC_STATIC) {
2955
36
          prop_value = &traits[i]->default_static_members_table[property_info->offset];
2956
36
          ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2957
82
        } else {
2958
82
          prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2959
82
        }
2960
118
        Z_TRY_ADDREF_P(prop_value);
2961
118
      } else {
2962
8
        prop_value = &tmp_prop_value;
2963
8
        ZVAL_UNDEF(&tmp_prop_value);
2964
8
      }
2965
2966
126
      zend_string *doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2967
2968
126
      zend_type type = property_info->type;
2969
      /* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2970
126
      zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2971
126
      zend_property_info *new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2972
2973
126
      if (property_info->attributes) {
2974
4
        new_prop->attributes = property_info->attributes;
2975
2976
4
        if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2977
0
          GC_ADDREF(new_prop->attributes);
2978
0
        }
2979
4
      }
2980
126
      if (property_info->hooks) {
2981
8
        zend_function **hooks = new_prop->hooks =
2982
8
          zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2983
8
        memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2984
24
        for (uint32_t j = 0; j < ZEND_PROPERTY_HOOK_COUNT; j++) {
2985
16
          if (hooks[j]) {
2986
10
            zend_function *old_fn = hooks[j];
2987
2988
            /* Hooks are not yet supported for internal properties. */
2989
10
            ZEND_ASSERT(ZEND_USER_CODE(old_fn->type));
2990
2991
            /* Copy the function, because we need to adjust the scope. */
2992
10
            zend_function *new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2993
10
            memcpy(new_fn, old_fn, sizeof(zend_op_array));
2994
10
            new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2995
10
            new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2996
10
            new_fn->common.prop_info = new_prop;
2997
10
            function_add_ref(new_fn);
2998
2999
10
            zend_fixup_trait_method(new_fn, ce);
3000
3001
10
            hooks[j] = new_fn;
3002
10
          }
3003
16
        }
3004
8
        ce->num_hooked_props++;
3005
8
      }
3006
126
    } ZEND_HASH_FOREACH_END();
3007
636
  }
3008
528
}
3009
/* }}} */
3010
3011
48
#define MAX_ABSTRACT_INFO_CNT 3
3012
#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
3013
#define DISPLAY_ABSTRACT_FN(idx) \
3014
60
  ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
3015
60
  ai.afn[idx] ? "::" : "", \
3016
60
  ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
3017
60
  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
28
{
3026
28
  if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
3027
24
    ai->afn[ai->cnt] = fn;
3028
24
  }
3029
28
  ai->cnt++;
3030
28
}
3031
/* }}} */
3032
3033
void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
3034
52
{
3035
52
  const zend_function *func;
3036
52
  zend_abstract_info ai;
3037
52
  bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
3038
52
  bool can_be_abstract = (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_ANON_CLASS)) == 0;
3039
52
  memset(&ai, 0, sizeof(ai));
3040
3041
312
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
3042
312
    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
34
      if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
3046
26
        zend_verify_abstract_class_function(func, &ai);
3047
26
      }
3048
34
    }
3049
312
  } ZEND_HASH_FOREACH_END();
3050
3051
52
  if (!is_explicit_abstract) {
3052
18
    const zend_property_info *prop_info;
3053
34
    ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
3054
34
      if (prop_info->hooks) {
3055
12
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3056
8
          const zend_function *fn = prop_info->hooks[i];
3057
8
          if (fn && (fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3058
2
            zend_verify_abstract_class_function(fn, &ai);
3059
2
          }
3060
8
        }
3061
4
      }
3062
34
    } ZEND_HASH_FOREACH_END();
3063
18
  }
3064
3065
52
  if (ai.cnt) {
3066
20
    if (!is_explicit_abstract && can_be_abstract) {
3067
18
      zend_error_noreturn(E_ERROR,
3068
18
        "%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
18
        zend_get_object_type_uc(ce),
3070
18
        ZSTR_VAL(ce->name), ai.cnt,
3071
18
        ai.cnt > 1 ? "s" : "",
3072
18
        ai.cnt > 1 ? "s" : "",
3073
18
        DISPLAY_ABSTRACT_FN(0),
3074
18
        DISPLAY_ABSTRACT_FN(1),
3075
18
        DISPLAY_ABSTRACT_FN(2)
3076
18
      );
3077
18
    } else {
3078
2
      zend_error_noreturn(E_ERROR,
3079
2
        "%s %s must implement %d abstract method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3080
2
        zend_get_object_type_uc(ce),
3081
2
        ZSTR_VAL(ce->name), ai.cnt,
3082
2
        ai.cnt > 1 ? "s" : "",
3083
2
        DISPLAY_ABSTRACT_FN(0),
3084
2
        DISPLAY_ABSTRACT_FN(1),
3085
2
        DISPLAY_ABSTRACT_FN(2)
3086
2
      );
3087
2
    }
3088
32
  } else {
3089
    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
3090
32
    ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3091
32
  }
3092
52
}
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
80
static void variance_obligation_dtor(zval *zv) {
3131
80
  efree(Z_PTR_P(zv));
3132
80
}
3133
3134
78
static void variance_obligation_ht_dtor(zval *zv) {
3135
78
  zend_hash_destroy(Z_PTR_P(zv));
3136
78
  FREE_HASHTABLE(Z_PTR_P(zv));
3137
78
}
3138
3139
80
static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
3140
80
  HashTable *ht;
3141
80
  zend_ulong key;
3142
80
  if (!CG(delayed_variance_obligations)) {
3143
58
    ALLOC_HASHTABLE(CG(delayed_variance_obligations));
3144
58
    zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
3145
58
  }
3146
3147
80
  key = (zend_ulong) (uintptr_t) ce;
3148
80
  ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
3149
80
  if (ht) {
3150
2
    return ht;
3151
2
  }
3152
3153
78
  ALLOC_HASHTABLE(ht);
3154
78
  zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
3155
78
  zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
3156
78
  ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
3157
78
  return ht;
3158
80
}
3159
3160
12
static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
3161
12
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3162
12
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3163
12
  obligation->type = OBLIGATION_DEPENDENCY;
3164
12
  obligation->dependency_ce = dependency_ce;
3165
12
  zend_hash_next_index_insert_ptr(obligations, obligation);
3166
12
}
3167
3168
static void add_compatibility_obligation(
3169
    zend_class_entry *ce,
3170
    const zend_function *child_fn, zend_class_entry *child_scope,
3171
64
    const zend_function *parent_fn, zend_class_entry *parent_scope) {
3172
64
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3173
64
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3174
64
  obligation->type = OBLIGATION_COMPATIBILITY;
3175
  /* Copy functions, because they may be stack-allocated in the case of traits. */
3176
64
  if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3177
0
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
3178
64
  } else {
3179
64
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
3180
64
  }
3181
64
  if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3182
4
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
3183
60
  } else {
3184
60
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
3185
60
  }
3186
64
  obligation->child_scope = child_scope;
3187
64
  obligation->parent_scope = parent_scope;
3188
64
  zend_hash_next_index_insert_ptr(obligations, obligation);
3189
64
}
3190
3191
static void add_property_compatibility_obligation(
3192
    zend_class_entry *ce, const zend_property_info *child_prop,
3193
4
    const zend_property_info *parent_prop, prop_variance variance) {
3194
4
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3195
4
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3196
4
  obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
3197
4
  obligation->child_prop = child_prop;
3198
4
  obligation->parent_prop = parent_prop;
3199
4
  obligation->variance = variance;
3200
4
  zend_hash_next_index_insert_ptr(obligations, obligation);
3201
4
}
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
70
static void check_variance_obligation(const variance_obligation *obligation) {
3228
70
  if (obligation->type == OBLIGATION_DEPENDENCY) {
3229
12
    zend_class_entry *dependency_ce = obligation->dependency_ce;
3230
12
    if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3231
10
      zend_class_entry *orig_linking_class = CG(current_linking_class);
3232
3233
10
      CG(current_linking_class) =
3234
10
        (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
3235
10
      resolve_delayed_variance_obligations(dependency_ce);
3236
10
      CG(current_linking_class) = orig_linking_class;
3237
10
    }
3238
58
  } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
3239
54
    inheritance_status status = zend_do_perform_implementation_check(
3240
54
      &obligation->child_fn, obligation->child_scope,
3241
54
      &obligation->parent_fn, obligation->parent_scope);
3242
54
    if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3243
38
      emit_incompatible_method_error(
3244
38
        &obligation->child_fn, obligation->child_scope,
3245
38
        &obligation->parent_fn, obligation->parent_scope, status);
3246
38
    }
3247
    /* Either the compatibility check was successful or only threw a warning. */
3248
54
  } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
3249
4
    verify_property_type_compatibility(obligation->parent_prop, obligation->child_prop, obligation->variance, true, true);
3250
4
  } 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
70
}
3265
3266
78
static void load_delayed_classes(const zend_class_entry *ce) {
3267
78
  HashTable *delayed_autoloads = CG(delayed_autoloads);
3268
78
  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
78
  HashPosition pos = 0;
3278
78
  zend_string *name;
3279
78
  zend_ulong idx;
3280
170
  while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
3281
170
      != HASH_KEY_NON_EXISTENT) {
3282
94
    zend_string_addref(name);
3283
94
    zend_hash_del(delayed_autoloads, name);
3284
94
    zend_lookup_class(name);
3285
94
    zend_string_release(name);
3286
94
    if (EG(exception)) {
3287
2
      zend_exception_uncaught_error(
3288
2
        "During inheritance of %s, while autoloading %s",
3289
2
        ZSTR_VAL(ce->name), ZSTR_VAL(name));
3290
2
    }
3291
94
  }
3292
78
}
3293
3294
68
static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
3295
68
  HashTable *all_obligations = CG(delayed_variance_obligations);
3296
68
  zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
3297
3298
68
  ZEND_ASSERT(all_obligations != NULL);
3299
68
  const HashTable *obligations = zend_hash_index_find_ptr(all_obligations, num_key);
3300
68
  ZEND_ASSERT(obligations != NULL);
3301
3302
68
  variance_obligation *obligation;
3303
208
  ZEND_HASH_FOREACH_PTR(obligations, obligation) {
3304
208
    check_variance_obligation(obligation);
3305
208
  } ZEND_HASH_FOREACH_END();
3306
3307
68
  zend_inheritance_check_override(ce);
3308
3309
68
  ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
3310
68
  ce->ce_flags |= ZEND_ACC_LINKED;
3311
68
  zend_hash_index_del(all_obligations, num_key);
3312
68
}
3313
3314
60
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
60
  if (CG(unlinked_uses)
3320
4
      && zend_hash_index_del(CG(unlinked_uses), (zend_ulong)(uintptr_t)ce) == SUCCESS) {
3321
4
    zend_exception_uncaught_error(
3322
4
      "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
3323
4
  }
3324
60
}
3325
3326
24.3k
#define zend_update_inherited_handler(handler) do { \
3327
24.3k
    if (ce->handler == (zend_function*)op_array) { \
3328
509
      ce->handler = (zend_function*)new_op_array; \
3329
509
    } \
3330
24.3k
  } while (0)
3331
3332
static zend_op_array *zend_lazy_method_load(
3333
1.90k
    const zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3334
1.90k
  ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3335
1.90k
  ZEND_ASSERT(op_array->scope == pce);
3336
1.90k
  ZEND_ASSERT(op_array->prototype == NULL);
3337
1.90k
  zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3338
1.90k
  memcpy(new_op_array, op_array, sizeof(zend_op_array));
3339
1.90k
  new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3340
1.90k
  new_op_array->scope = ce;
3341
1.90k
  ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3342
1.90k
  ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3343
3344
1.90k
  return new_op_array;
3345
1.90k
}
3346
3347
static zend_class_entry *zend_lazy_class_load(const zend_class_entry *pce)
3348
1.98k
{
3349
1.98k
  zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3350
3351
1.98k
  memcpy(ce, pce, sizeof(zend_class_entry));
3352
1.98k
  ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3353
1.98k
  ce->refcount = 1;
3354
1.98k
  ce->inheritance_cache = NULL;
3355
1.98k
  if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3356
0
    ZEND_MAP_PTR_NEW(ce->mutable_data);
3357
1.98k
  } else {
3358
1.98k
    ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3359
1.98k
  }
3360
3361
  /* properties */
3362
1.98k
  if (ce->default_properties_table) {
3363
576
    zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3364
576
    zval *src = ce->default_properties_table;
3365
576
    const zval *end = src + ce->default_properties_count;
3366
3367
576
    ce->default_properties_table = dst;
3368
1.37k
    for (; src != end; src++, dst++) {
3369
798
      ZVAL_COPY_VALUE_PROP(dst, src);
3370
798
    }
3371
576
  }
3372
3373
  /* methods */
3374
1.98k
  ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3375
1.98k
  if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3376
905
    Bucket *p = emalloc(HT_SIZE(&ce->function_table));
3377
905
    memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3378
905
    HT_SET_DATA_ADDR(&ce->function_table, p);
3379
905
    p = ce->function_table.arData;
3380
905
    const Bucket *end = p + ce->function_table.nNumUsed;
3381
2.77k
    for (; p != end; p++) {
3382
1.87k
      zend_op_array *op_array = Z_PTR(p->val);
3383
1.87k
      zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3384
3385
1.87k
      zend_update_inherited_handler(constructor);
3386
1.87k
      zend_update_inherited_handler(destructor);
3387
1.87k
      zend_update_inherited_handler(clone);
3388
1.87k
      zend_update_inherited_handler(__get);
3389
1.87k
      zend_update_inherited_handler(__set);
3390
1.87k
      zend_update_inherited_handler(__call);
3391
1.87k
      zend_update_inherited_handler(__isset);
3392
1.87k
      zend_update_inherited_handler(__unset);
3393
1.87k
      zend_update_inherited_handler(__tostring);
3394
1.87k
      zend_update_inherited_handler(__callstatic);
3395
1.87k
      zend_update_inherited_handler(__debugInfo);
3396
1.87k
      zend_update_inherited_handler(__serialize);
3397
1.87k
      zend_update_inherited_handler(__unserialize);
3398
1.87k
    }
3399
905
  }
3400
3401
  /* static members */
3402
1.98k
  if (ce->default_static_members_table) {
3403
22
    zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
3404
22
    zval *src = ce->default_static_members_table;
3405
22
    const zval *end = src + ce->default_static_members_count;
3406
3407
22
    ce->default_static_members_table = dst;
3408
50
    for (; src != end; src++, dst++) {
3409
28
      ZVAL_COPY_VALUE(dst, src);
3410
28
    }
3411
22
  }
3412
1.98k
  ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3413
3414
  /* properties_info */
3415
1.98k
  if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3416
606
    Bucket *p = emalloc(HT_SIZE(&ce->properties_info));
3417
606
    memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3418
606
    HT_SET_DATA_ADDR(&ce->properties_info, p);
3419
606
    p = ce->properties_info.arData;
3420
606
    const Bucket *end = p + ce->properties_info.nNumUsed;
3421
1.46k
    for (; p != end; p++) {
3422
854
      zend_property_info *new_prop_info;
3423
3424
854
      const zend_property_info *prop_info = Z_PTR(p->val);
3425
854
      ZEND_ASSERT(prop_info->ce == pce);
3426
854
      ZEND_ASSERT(prop_info->prototype == prop_info);
3427
854
      new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3428
854
      Z_PTR(p->val) = new_prop_info;
3429
854
      memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3430
854
      new_prop_info->ce = ce;
3431
854
      new_prop_info->prototype = new_prop_info;
3432
      /* Deep copy the type information */
3433
854
      zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3434
854
      if (new_prop_info->hooks) {
3435
28
        new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3436
28
        memcpy(new_prop_info->hooks, prop_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3437
84
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3438
56
          if (new_prop_info->hooks[i]) {
3439
30
            zend_op_array *hook = zend_lazy_method_load((zend_op_array *) new_prop_info->hooks[i], ce, pce);
3440
30
            ZEND_ASSERT(hook->prop_info == prop_info);
3441
30
            hook->prop_info = new_prop_info;
3442
30
            new_prop_info->ce = ce;
3443
30
            new_prop_info->hooks[i] = (zend_function *) hook;
3444
30
          }
3445
56
        }
3446
28
      }
3447
854
    }
3448
606
  }
3449
3450
  /* constants table */
3451
1.98k
  if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3452
376
    Bucket *p = emalloc(HT_SIZE(&ce->constants_table));
3453
376
    memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3454
376
    HT_SET_DATA_ADDR(&ce->constants_table, p);
3455
376
    p = ce->constants_table.arData;
3456
376
    const Bucket *end = p + ce->constants_table.nNumUsed;
3457
1.06k
    for (; p != end; p++) {
3458
688
      zend_class_constant *new_c;
3459
3460
688
      const zend_class_constant *c = Z_PTR(p->val);
3461
688
      ZEND_ASSERT(c->ce == pce);
3462
688
      new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3463
688
      Z_PTR(p->val) = new_c;
3464
688
      memcpy(new_c, c, sizeof(zend_class_constant));
3465
688
      new_c->ce = ce;
3466
688
    }
3467
376
  }
3468
3469
1.98k
  return ce;
3470
1.98k
}
3471
3472
#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
3473
4.32k
# define UPDATE_IS_CACHEABLE(ce) do { \
3474
4.32k
      if ((ce)->type == ZEND_USER_CLASS) { \
3475
3.07k
        is_cacheable &= (ce)->ce_flags; \
3476
3.07k
      } \
3477
4.32k
    } 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
2.08k
{
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
2.08k
  zend_class_entry *parent = NULL;
3491
2.08k
  zend_class_entry **traits_and_interfaces = NULL;
3492
2.08k
  zend_class_entry *proto = NULL;
3493
2.08k
  zend_class_entry *orig_linking_class;
3494
2.08k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3495
2.08k
  uint32_t i, j;
3496
2.08k
  zval *zv;
3497
2.08k
  ALLOCA_FLAG(use_heap)
3498
3499
2.08k
  SET_ALLOCA_FLAG(use_heap);
3500
2.08k
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3501
3502
2.08k
  if (ce->parent_name) {
3503
484
    parent = zend_fetch_class_by_name(
3504
484
      ce->parent_name, lc_parent_name,
3505
484
      ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3506
484
    if (!parent) {
3507
38
      check_unrecoverable_load_failure(ce);
3508
38
      return NULL;
3509
38
    }
3510
446
    UPDATE_IS_CACHEABLE(parent);
3511
446
  }
3512
3513
2.04k
  if (ce->num_traits || ce->num_interfaces) {
3514
1.79k
    traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3515
3516
2.50k
    for (i = 0; i < ce->num_traits; i++) {
3517
716
      zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3518
716
        ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
3519
716
      if (UNEXPECTED(trait == NULL)) {
3520
6
        free_alloca(traits_and_interfaces, use_heap);
3521
6
        return NULL;
3522
6
      }
3523
710
      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
710
      if (UNEXPECTED(trait->ce_flags & ZEND_ACC_DEPRECATED)) {
3529
28
        zend_use_of_deprecated_trait(trait, ce->name);
3530
28
        if (UNEXPECTED(EG(exception))) {
3531
2
          free_alloca(traits_and_interfaces, use_heap);
3532
2
          return NULL;
3533
2
        }
3534
28
      }
3535
868
      for (j = 0; j < i; j++) {
3536
166
        if (traits_and_interfaces[j] == trait) {
3537
          /* skip duplications */
3538
6
          trait = NULL;
3539
6
          break;
3540
6
        }
3541
166
      }
3542
708
      traits_and_interfaces[i] = trait;
3543
708
      if (trait) {
3544
702
        UPDATE_IS_CACHEABLE(trait);
3545
702
      }
3546
708
    }
3547
1.79k
  }
3548
3549
2.04k
  if (ce->num_interfaces) {
3550
2.81k
    for (i = 0; i < ce->num_interfaces; i++) {
3551
1.57k
      zend_class_entry *iface = zend_fetch_class_by_name(
3552
1.57k
        ce->interface_names[i].name, ce->interface_names[i].lc_name,
3553
1.57k
        ZEND_FETCH_CLASS_INTERFACE |
3554
1.57k
        ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3555
1.57k
      if (!iface) {
3556
22
        check_unrecoverable_load_failure(ce);
3557
22
        free_alloca(traits_and_interfaces, use_heap);
3558
22
        return NULL;
3559
22
      }
3560
1.54k
      traits_and_interfaces[ce->num_traits + i] = iface;
3561
1.54k
      if (iface) {
3562
1.54k
        UPDATE_IS_CACHEABLE(iface);
3563
1.54k
      }
3564
1.54k
    }
3565
1.26k
  }
3566
3567
2.01k
#ifndef ZEND_WIN32
3568
2.01k
  if (ce->ce_flags & ZEND_ACC_ENUM) {
3569
    /* We will add internal methods. */
3570
354
    is_cacheable = false;
3571
354
  }
3572
2.01k
#endif
3573
3574
2.01k
  if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3575
1.59k
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3576
1.59k
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3577
1.59k
      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
1.59k
    } else {
3586
0
      is_cacheable = 0;
3587
0
    }
3588
1.59k
    proto = ce;
3589
1.59k
  }
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
2.01k
  bool orig_record_errors = EG(record_errors);
3596
2.01k
  if (!orig_record_errors) {
3597
2.01k
    zend_begin_record_errors();
3598
2.01k
  }
3599
3600
2.01k
  zend_try {
3601
2.01k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3602
      /* Lazy class loading */
3603
1.96k
      ce = zend_lazy_class_load(ce);
3604
1.96k
      zv = zend_hash_find_known_hash(CG(class_table), key);
3605
1.96k
      Z_CE_P(zv) = ce;
3606
1.96k
    } 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
2.01k
    if (CG(unlinked_uses)) {
3615
18
      zend_hash_index_del(CG(unlinked_uses), (zend_ulong)(uintptr_t) ce);
3616
18
    }
3617
3618
2.01k
    orig_linking_class = CG(current_linking_class);
3619
2.01k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3620
3621
2.01k
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3622
      /* Only register builtin enum methods during inheritance to avoid persisting them in
3623
       * opcache. */
3624
354
      zend_enum_register_funcs(ce);
3625
354
    }
3626
3627
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3628
    zend_link_hooked_object_iter(ce);
3629
#endif
3630
3631
2.01k
    HashTable **trait_exclude_tables;
3632
2.01k
    zend_class_entry **trait_aliases;
3633
2.01k
    bool trait_contains_abstract_methods = false;
3634
2.01k
    if (ce->num_traits) {
3635
568
      zend_traits_init_trait_structures(ce, traits_and_interfaces, &trait_exclude_tables, &trait_aliases);
3636
568
      zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods);
3637
568
      zend_do_traits_constant_binding(ce, traits_and_interfaces);
3638
568
      zend_do_traits_property_binding(ce, traits_and_interfaces);
3639
3640
568
      zend_function *fn;
3641
2.66k
      ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3642
2.66k
        zend_fixup_trait_method(fn, ce);
3643
2.66k
      } ZEND_HASH_FOREACH_END();
3644
568
    }
3645
2.01k
    if (parent) {
3646
426
      if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3647
12
        add_dependency_obligation(ce, parent);
3648
12
      }
3649
426
      zend_do_inheritance(ce, parent);
3650
426
    }
3651
1.96k
    if (ce->num_traits) {
3652
514
      if (trait_contains_abstract_methods) {
3653
68
        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
68
        zend_function *fn;
3658
368
        ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3659
368
          zend_fixup_trait_method(fn, ce);
3660
368
        } ZEND_HASH_FOREACH_END();
3661
68
      }
3662
3663
514
      if (trait_exclude_tables) {
3664
58
        for (i = 0; i < ce->num_traits; i++) {
3665
40
          if (traits_and_interfaces[i]) {
3666
40
            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
40
          }
3671
40
        }
3672
18
        efree(trait_exclude_tables);
3673
18
      }
3674
506
      if (trait_aliases) {
3675
74
        efree(trait_aliases);
3676
74
      }
3677
506
    }
3678
1.96k
    if (ce->num_interfaces) {
3679
      /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3680
1.24k
      uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3681
1.24k
      zend_class_entry **interfaces = emalloc(
3682
1.24k
          sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3683
3684
1.24k
      if (num_parent_interfaces) {
3685
30
        memcpy(interfaces, parent->interfaces,
3686
30
             sizeof(zend_class_entry *) * num_parent_interfaces);
3687
30
      }
3688
1.24k
      memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3689
1.24k
           sizeof(zend_class_entry *) * ce->num_interfaces);
3690
3691
1.24k
      zend_do_implement_interfaces(ce, interfaces);
3692
1.24k
    } else if (parent && parent->num_interfaces) {
3693
46
      zend_do_inherit_interfaces(ce, parent);
3694
46
    }
3695
1.95k
    if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3696
1.80k
      && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3697
1.95k
        ) {
3698
50
      zend_verify_abstract_class(ce);
3699
50
    }
3700
1.95k
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3701
354
      zend_verify_enum(ce);
3702
354
    }
3703
1.95k
    if (ce->num_hooked_prop_variance_checks) {
3704
2
      const zend_property_info *prop_info;
3705
8
      ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
3706
8
        if (prop_info->ce == ce && prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
3707
2
          switch (zend_verify_property_hook_variance(prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
3708
2
            case INHERITANCE_SUCCESS:
3709
2
              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
2
          }
3719
2
        }
3720
8
      } ZEND_HASH_FOREACH_END();
3721
2
    }
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
1.95k
    if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3726
221
      && !zend_class_implements_interface(ce, zend_ce_stringable)) {
3727
6
      ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
3728
6
      ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
3729
6
      ce->num_interfaces++;
3730
6
      ce->interfaces = perealloc(ce->interfaces,
3731
6
                     sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
3732
6
      ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
3733
6
      do_interface_implementation(ce, zend_ce_stringable);
3734
6
    }
3735
3736
1.95k
    zend_build_properties_info_table(ce);
3737
1.95k
  } zend_catch {
3738
    /* Do not leak recorded errors to the next linked class. */
3739
136
    if (!orig_record_errors) {
3740
136
      EG(record_errors) = false;
3741
136
      zend_free_recorded_errors();
3742
136
    }
3743
136
    zend_bailout();
3744
1.87k
  } zend_end_try();
3745
3746
1.87k
  EG(record_errors) = orig_record_errors;
3747
3748
1.87k
  if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3749
1.79k
    zend_inheritance_check_override(ce);
3750
1.79k
    ce->ce_flags |= ZEND_ACC_LINKED;
3751
1.79k
  } else {
3752
78
    ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
3753
78
    if (CG(current_linking_class)) {
3754
62
      ce->ce_flags |= ZEND_ACC_CACHEABLE;
3755
62
    }
3756
78
    load_delayed_classes(ce);
3757
78
    if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3758
58
      resolve_delayed_variance_obligations(ce);
3759
58
    }
3760
78
    if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3761
4
      ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3762
74
    } else {
3763
74
      CG(current_linking_class) = NULL;
3764
74
    }
3765
78
  }
3766
3767
1.87k
  if (!CG(current_linking_class)) {
3768
412
    is_cacheable = 0;
3769
412
  }
3770
1.87k
  CG(current_linking_class) = orig_linking_class;
3771
3772
1.87k
  if (is_cacheable) {
3773
1.40k
    HashTable *ht = (HashTable*)ce->inheritance_cache;
3774
1.40k
    zend_class_entry *new_ce;
3775
3776
1.40k
    ce->inheritance_cache = NULL;
3777
1.40k
    new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3778
1.40k
    if (new_ce) {
3779
1.40k
      zv = zend_hash_find_known_hash(CG(class_table), key);
3780
1.40k
      ce = new_ce;
3781
1.40k
      Z_CE_P(zv) = ce;
3782
1.40k
    }
3783
1.40k
    if (ht) {
3784
44
      zend_hash_destroy(ht);
3785
44
      FREE_HASHTABLE(ht);
3786
44
    }
3787
1.40k
  }
3788
3789
1.87k
  if (!orig_record_errors) {
3790
1.81k
    zend_emit_recorded_errors();
3791
1.81k
    zend_free_recorded_errors();
3792
1.81k
  }
3793
1.87k
  if (traits_and_interfaces) {
3794
1.63k
    free_alloca(traits_and_interfaces, use_heap);
3795
1.63k
  }
3796
3797
1.87k
  if (ZSTR_HAS_CE_CACHE(ce->name)) {
3798
1.74k
    ZSTR_SET_CE_CACHE(ce->name, ce);
3799
1.74k
  }
3800
3801
1.87k
  return ce;
3802
1.87k
}
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
1.62k
{
3808
1.62k
  zend_string *key;
3809
1.62k
  zend_function *parent_func;
3810
1.62k
  const zend_property_info *parent_info;
3811
1.62k
  const zend_class_constant *parent_const;
3812
1.62k
  inheritance_status overall_status = INHERITANCE_SUCCESS;
3813
3814
10.9k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3815
10.9k
    zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3816
10.9k
    if (zv) {
3817
780
      zend_function *child_func = Z_FUNC_P(zv);
3818
780
      inheritance_status status =
3819
780
        do_inheritance_check_on_method(
3820
780
          child_func, child_func->common.scope,
3821
780
          parent_func, parent_func->common.scope,
3822
780
          ce, NULL,
3823
780
          ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3824
780
      if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3825
12
        overall_status = INHERITANCE_WARNING;
3826
768
      } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3827
162
        return status;
3828
162
      }
3829
780
    }
3830
10.9k
  } ZEND_HASH_FOREACH_END();
3831
3832
6.50k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3833
6.50k
    const zval *zv;
3834
6.50k
    if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3835
1.19k
      continue;
3836
1.19k
    }
3837
3838
600
    zv = zend_hash_find_known_hash(&ce->properties_info, key);
3839
600
    if (zv) {
3840
148
      const zend_property_info *child_info = Z_PTR_P(zv);
3841
148
      if (ZEND_TYPE_IS_SET(child_info->type)) {
3842
146
        inheritance_status status = verify_property_type_compatibility(parent_info, child_info, prop_get_variance(parent_info), false, false);
3843
146
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3844
26
          return status;
3845
26
        }
3846
146
      }
3847
148
    }
3848
600
  } ZEND_HASH_FOREACH_END();
3849
3850
3.87k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3851
3.87k
    const zval *zv;
3852
3.87k
    if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3853
160
      continue;
3854
160
    }
3855
3856
340
    zv = zend_hash_find_known_hash(&ce->constants_table, key);
3857
340
    if (zv) {
3858
10
      const zend_class_constant *child_const = Z_PTR_P(zv);
3859
10
      if (ZEND_TYPE_IS_SET(child_const->type)) {
3860
10
        inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3861
10
        ZEND_ASSERT(status != INHERITANCE_WARNING);
3862
10
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3863
4
          return status;
3864
4
        }
3865
10
      }
3866
10
    }
3867
340
  } ZEND_HASH_FOREACH_END();
3868
3869
1.43k
  return overall_status;
3870
1.43k
}
3871
/* }}} */
3872
3873
1.52k
static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3874
1.52k
  if (delayed_early_binding) {
3875
12
    if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3876
12
      if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3877
12
        Z_CE_P(delayed_early_binding) = ce;
3878
12
        return true;
3879
12
      }
3880
12
    } 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
1.51k
  if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3892
1.50k
    return true;
3893
1.50k
  }
3894
12
  return false;
3895
1.51k
}
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
1.62k
{
3899
1.62k
  inheritance_status status;
3900
1.62k
  zend_class_entry *proto = NULL;
3901
1.62k
  zend_class_entry *orig_linking_class;
3902
3903
1.62k
  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
1.62k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3913
1.62k
  UPDATE_IS_CACHEABLE(parent_ce);
3914
1.62k
  if (is_cacheable) {
3915
58
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3916
58
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3917
58
      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
58
    } else {
3925
0
      is_cacheable = 0;
3926
0
    }
3927
58
    proto = ce;
3928
58
  }
3929
3930
1.62k
  orig_linking_class = CG(current_linking_class);
3931
1.62k
  CG(current_linking_class) = NULL;
3932
1.62k
  status = zend_can_early_bind(ce, parent_ce);
3933
1.62k
  CG(current_linking_class) = orig_linking_class;
3934
1.62k
  if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3935
1.52k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3936
      /* Lazy class loading */
3937
12
      ce = zend_lazy_class_load(ce);
3938
1.51k
    } 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
1.52k
    if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3945
12
      return NULL;
3946
12
    }
3947
3948
1.51k
    orig_linking_class = CG(current_linking_class);
3949
1.51k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3950
3951
1.51k
    bool orig_record_errors = EG(record_errors);
3952
3953
1.51k
    zend_try{
3954
1.51k
      CG(zend_lineno) = ce->info.user.line_start;
3955
3956
1.51k
      if (!orig_record_errors) {
3957
30
        zend_begin_record_errors();
3958
30
      }
3959
3960
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3961
      zend_link_hooked_object_iter(ce);
3962
#endif
3963
3964
1.51k
      zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3965
1.51k
      if (parent_ce && parent_ce->num_interfaces) {
3966
118
        zend_do_inherit_interfaces(ce, parent_ce);
3967
118
      }
3968
1.51k
      zend_build_properties_info_table(ce);
3969
1.51k
      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
2
        zend_verify_abstract_class(ce);
3971
2
      }
3972
1.51k
      zend_inheritance_check_override(ce);
3973
1.51k
      ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3974
1.51k
      ce->ce_flags |= ZEND_ACC_LINKED;
3975
3976
1.41k
      CG(current_linking_class) = orig_linking_class;
3977
1.41k
    } zend_catch {
3978
102
      if (!orig_record_errors) {
3979
2
        EG(record_errors) = false;
3980
2
        zend_free_recorded_errors();
3981
2
      }
3982
102
      zend_bailout();
3983
1.41k
    } zend_end_try();
3984
3985
1.41k
    if (is_cacheable) {
3986
12
      HashTable *ht = (HashTable*)ce->inheritance_cache;
3987
12
      zend_class_entry *new_ce;
3988
3989
12
      ce->inheritance_cache = NULL;
3990
12
      new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3991
12
      if (new_ce) {
3992
12
        zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3993
12
        ce = new_ce;
3994
12
        Z_CE_P(zv) = ce;
3995
12
      }
3996
12
      if (ht) {
3997
0
        zend_hash_destroy(ht);
3998
0
        FREE_HASHTABLE(ht);
3999
0
      }
4000
12
    }
4001
4002
1.41k
    if (!orig_record_errors) {
4003
28
      zend_emit_recorded_errors();
4004
28
      zend_free_recorded_errors();
4005
28
    }
4006
4007
1.41k
    if (ZSTR_HAS_CE_CACHE(ce->name)) {
4008
1.29k
      ZSTR_SET_CE_CACHE(ce->name, ce);
4009
1.29k
    }
4010
1.41k
    zend_observer_class_linked_notify(ce, lcname);
4011
4012
1.41k
    return ce;
4013
1.41k
  }
4014
96
  return NULL;
4015
1.62k
}
4016
/* }}} */