Coverage Report

Created: 2025-12-14 06:05

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