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