Coverage Report

Created: 2026-06-02 06:36

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