Coverage Report

Created: 2026-01-18 06:48

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