Coverage Report

Created: 2026-01-18 06:49

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
0
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
92
0
  if (ZEND_TYPE_HAS_LIST(*type)) {
93
0
    zend_type_list_copy_ctor(type, use_arena, persistent);
94
0
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
95
0
    zend_string_addref(ZEND_TYPE_NAME(*type));
96
0
  }
97
0
}
98
99
static zend_function *zend_duplicate_internal_function(const zend_function *func, const zend_class_entry *ce) /* {{{ */
100
2.37k
{
101
2.37k
  zend_function *new_function;
102
103
2.37k
  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
48
    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
108
48
    memcpy(new_function, func, sizeof(zend_internal_function));
109
48
    new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
110
48
  }
111
2.37k
  if (EXPECTED(new_function->common.function_name)) {
112
2.37k
    zend_string_addref(new_function->common.function_name);
113
2.37k
  }
114
2.37k
  return new_function;
115
2.37k
}
116
/* }}} */
117
118
static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
119
2.45k
{
120
2.45k
  if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
121
2.37k
    return zend_duplicate_internal_function(func, ce);
122
2.37k
  } else {
123
82
    if (func->op_array.refcount) {
124
82
      (*func->op_array.refcount)++;
125
82
    }
126
82
    if (EXPECTED(func->op_array.function_name)) {
127
82
      zend_string_addref(func->op_array.function_name);
128
82
    }
129
82
    return func;
130
82
  }
131
2.45k
}
132
/* }}} */
133
134
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
135
195
{
136
195
  zend_class_entry *parent = ce->parent;
137
138
195
  ZEND_ASSERT(parent != NULL);
139
140
  /* You cannot change create_object */
141
195
  ce->create_object = parent->create_object;
142
143
  /* Inherit special functions if needed */
144
195
  if (EXPECTED(!ce->get_iterator)) {
145
187
    ce->get_iterator = parent->get_iterator;
146
187
  }
147
195
  if (EXPECTED(!ce->__get)) {
148
195
    ce->__get = parent->__get;
149
195
  }
150
195
  if (EXPECTED(!ce->__set)) {
151
195
    ce->__set = parent->__set;
152
195
  }
153
195
  if (EXPECTED(!ce->__unset)) {
154
195
    ce->__unset = parent->__unset;
155
195
  }
156
195
  if (EXPECTED(!ce->__isset)) {
157
195
    ce->__isset = parent->__isset;
158
195
  }
159
195
  if (EXPECTED(!ce->__call)) {
160
195
    ce->__call = parent->__call;
161
195
  }
162
195
  if (EXPECTED(!ce->__callstatic)) {
163
195
    ce->__callstatic = parent->__callstatic;
164
195
  }
165
195
  if (EXPECTED(!ce->__tostring)) {
166
185
    ce->__tostring = parent->__tostring;
167
185
  }
168
195
  if (EXPECTED(!ce->clone)) {
169
195
    ce->clone = parent->clone;
170
195
  }
171
195
  if (EXPECTED(!ce->__serialize)) {
172
195
    ce->__serialize = parent->__serialize;
173
195
  }
174
195
  if (EXPECTED(!ce->__unserialize)) {
175
195
    ce->__unserialize = parent->__unserialize;
176
195
  }
177
195
  if (EXPECTED(!ce->serialize)) {
178
195
    ce->serialize = parent->serialize;
179
195
  }
180
195
  if (EXPECTED(!ce->unserialize)) {
181
195
    ce->unserialize = parent->unserialize;
182
195
  }
183
195
  if (!ce->destructor) {
184
194
    ce->destructor = parent->destructor;
185
194
  }
186
195
  if (EXPECTED(!ce->__debugInfo)) {
187
195
    ce->__debugInfo = parent->__debugInfo;
188
195
  }
189
190
195
  if (ce->constructor) {
191
60
    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
60
    return;
197
60
  }
198
199
135
  ce->constructor = parent->constructor;
200
135
}
201
/* }}} */
202
203
const char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
204
5.51k
{
205
5.51k
  if (fn_flags & ZEND_ACC_PUBLIC) {
206
5.49k
    return "public";
207
5.49k
  } else if (fn_flags & ZEND_ACC_PRIVATE) {
208
16
    return "private";
209
16
  } else {
210
9
    ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
211
9
    return "protected";
212
9
  }
213
5.51k
}
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
119
static zend_string *resolve_class_name(const zend_class_entry *scope, zend_string *name) {
229
119
  ZEND_ASSERT(scope);
230
119
  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
119
  } else if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_SELF))) {
237
0
    return scope->name;
238
119
  } else {
239
119
    return name;
240
119
  }
241
119
}
242
243
13
static bool class_visible(const zend_class_entry *ce) {
244
13
  if (ce->type == ZEND_INTERNAL_CLASS) {
245
13
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
246
13
  } 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
13
}
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
79
    zend_class_entry *scope, zend_string *name, bool register_unresolved) {
264
79
  zend_class_entry *ce;
265
79
  bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
266
267
79
  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
35
  ce = zend_lookup_class_ex(
284
35
      name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
285
286
35
  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
35
  } else {
295
35
    if (ce && class_visible(ce)) {
296
13
      return ce;
297
13
    }
298
299
    /* The current class may not be registered yet, so check for it explicitly. */
300
22
    if (zend_string_equals_ci(scope->name, name)) {
301
0
      return scope;
302
0
    }
303
22
  }
304
305
22
  return NULL;
306
35
}
307
308
68
static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name) {
309
68
  return lookup_class_ex(scope, name, /* register_unresolved */ false);
310
68
}
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
57
{
388
57
  HashTable *ht;
389
390
57
  ZEND_ASSERT(class_name);
391
57
  if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
392
57
    return;
393
57
  } 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
66
    zend_class_entry *proto_scope, const zend_type proto_type) {
477
66
  zend_class_entry *fe_ce = NULL;
478
66
  bool have_unresolved = false;
479
480
  /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
481
66
  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
66
  if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_CALLABLE) {
496
24
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
497
24
    if (!fe_ce) {
498
11
      have_unresolved = true;
499
13
    } else if (fe_ce == zend_ce_closure) {
500
13
      track_class_dependency(fe_ce, fe_class_name);
501
13
      return INHERITANCE_SUCCESS;
502
13
    }
503
24
  }
504
505
  /* If the parent has 'static' as a return type, then final classes could replace it with self */
506
53
  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
53
  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
53
  bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
521
106
  ZEND_TYPE_FOREACH(proto_type, single_type) {
522
106
    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
53
    zend_class_entry *proto_ce;
545
53
    zend_string *proto_class_name = NULL;
546
53
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
547
42
      proto_class_name =
548
42
        resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
549
42
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
550
20
        if (!is_intersection) {
551
20
          return INHERITANCE_SUCCESS;
552
20
        }
553
0
        continue;
554
20
      }
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
11
      ZEND_ASSERT(!is_intersection);
561
11
      continue;
562
11
    }
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
11
  if (have_unresolved) {
582
11
    return INHERITANCE_UNRESOLVED;
583
11
  }
584
0
  return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
585
11
}
586
587
505
static zend_string *get_class_from_type(const zend_class_entry *scope, const zend_type single_type) {
588
505
  if (ZEND_TYPE_HAS_NAME(single_type)) {
589
66
    return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
590
66
  }
591
439
  return NULL;
592
505
}
593
594
22
static void register_unresolved_classes(zend_class_entry *scope, const zend_type type) {
595
22
  const zend_type *single_type;
596
44
  ZEND_TYPE_FOREACH(type, single_type) {
597
44
    if (ZEND_TYPE_HAS_LIST(*single_type)) {
598
0
      register_unresolved_classes(scope, *single_type);
599
0
      continue;
600
0
    }
601
22
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
602
11
      zend_string *class_name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
603
11
      lookup_class_ex(scope, class_name, /* register_unresolved */ true);
604
11
    }
605
22
  } ZEND_TYPE_FOREACH_END();
606
22
}
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
617
{
678
617
  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
617
  if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
683
112
      !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
684
112
    return INHERITANCE_SUCCESS;
685
112
  }
686
687
  /* Builtin types may be removed, but not added */
688
505
  uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
689
505
  uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
690
505
  uint32_t added_types = fe_type_mask & ~proto_type_mask;
691
505
  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
505
  inheritance_status early_exit_status;
710
505
  bool have_unresolved = false;
711
712
505
  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
505
  } 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
505
    early_exit_status = INHERITANCE_ERROR;
730
505
    const zend_type *single_type;
731
1.01k
    ZEND_TYPE_FOREACH(fe_type, single_type) {
732
1.01k
      inheritance_status status;
733
      /* Union has an intersection type as it's member */
734
1.01k
      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
505
      } else {
738
505
        zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
739
505
        if (!fe_class_name) {
740
439
          continue;
741
439
        }
742
743
66
        status = zend_is_class_subtype_of_type(
744
66
          fe_scope, fe_class_name, proto_scope, proto_type);
745
66
      }
746
747
66
      if (status == early_exit_status) {
748
0
        return status;
749
0
      }
750
66
      if (status == INHERITANCE_UNRESOLVED) {
751
11
        have_unresolved = true;
752
11
      }
753
66
    } ZEND_TYPE_FOREACH_END();
754
505
  }
755
756
505
  if (!have_unresolved) {
757
494
    return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
758
494
  }
759
760
11
  register_unresolved_classes(fe_scope, fe_type);
761
11
  register_unresolved_classes(proto_scope, proto_type);
762
11
  return INHERITANCE_UNRESOLVED;
763
505
}
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
143
{
769
143
  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
87
    return INHERITANCE_SUCCESS;
772
87
  }
773
774
56
  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
56
  return zend_perform_covariant_type_check(
782
56
    proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
783
56
}
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
596
{
793
596
  uint32_t num_args, proto_num_args, fe_num_args;
794
596
  inheritance_status status, local_status;
795
596
  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
596
  ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
801
596
    && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
802
596
      && (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
596
  ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
807
596
      || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
808
809
  /* The number of required arguments cannot increase. */
810
596
  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
596
  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
596
  proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
821
596
  fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
822
823
  /* A variadic function cannot become non-variadic */
824
596
  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
596
  proto_num_args = proto->common.num_args + proto_is_variadic;
830
596
  fe_num_args = fe->common.num_args + fe_is_variadic;
831
596
  num_args = MAX(proto_num_args, fe_num_args);
832
833
596
  status = INHERITANCE_SUCCESS;
834
743
  for (uint32_t i = 0; i < num_args; i++) {
835
147
    zend_arg_info *proto_arg_info =
836
147
      i < proto_num_args ? &proto->common.arg_info[i] :
837
147
      proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
838
147
    zend_arg_info *fe_arg_info =
839
147
      i < fe_num_args ? &fe->common.arg_info[i] :
840
147
      fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
841
147
    if (!proto_arg_info) {
842
      /* A new (optional) argument has been added, which is fine. */
843
4
      continue;
844
4
    }
845
143
    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
143
    local_status = zend_do_perform_arg_type_hint_check(
853
143
      fe_scope, fe_arg_info, proto_scope, proto_arg_info);
854
855
143
    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
143
    if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
865
0
      return INHERITANCE_ERROR;
866
0
    }
867
143
  }
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
596
  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
564
    if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
874
4
      if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
875
0
        return INHERITANCE_ERROR;
876
0
      }
877
4
      if (status == INHERITANCE_SUCCESS) {
878
4
        return INHERITANCE_WARNING;
879
4
      }
880
0
      return status;
881
4
    }
882
883
560
    local_status = zend_perform_covariant_type_check(
884
560
      fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
885
886
560
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
887
11
      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
11
      return local_status;
892
11
    }
893
560
  }
894
895
581
  return status;
896
596
}
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
6
{
902
6
  if (ZEND_TYPE_IS_SET(arg_info->type)) {
903
6
    zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
904
6
    smart_str_append(str, type_str);
905
6
    zend_string_release(type_str);
906
6
    if (!return_hint) {
907
4
      smart_str_appendc(str, ' ');
908
4
    }
909
6
  }
910
6
}
911
/* }}} */
912
913
static ZEND_COLD zend_string *zend_get_function_declaration(
914
    const zend_function *fptr, zend_class_entry *scope) /* {{{ */
915
4
{
916
4
  smart_str str = {0};
917
918
4
  if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
919
0
    smart_str_appendc(&str, '&');
920
0
  }
921
922
4
  if (fptr->common.scope) {
923
4
    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
4
    } else {
927
4
      smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), ZSTR_LEN(fptr->common.scope->name));
928
4
    }
929
4
    smart_str_appends(&str, "::");
930
4
  }
931
932
4
  smart_str_append(&str, fptr->common.function_name);
933
4
  smart_str_appendc(&str, '(');
934
935
4
  if (fptr->common.arg_info) {
936
4
    uint32_t num_args, required;
937
4
    zend_arg_info *arg_info = fptr->common.arg_info;
938
939
4
    required = fptr->common.required_num_args;
940
4
    num_args = fptr->common.num_args;
941
4
    if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
942
0
      num_args++;
943
0
    }
944
8
    for (uint32_t i = 0; i < num_args;) {
945
4
      zend_append_type_hint(&str, scope, arg_info, false);
946
947
4
      if (ZEND_ARG_SEND_MODE(arg_info)) {
948
0
        smart_str_appendc(&str, '&');
949
0
      }
950
951
4
      if (ZEND_ARG_IS_VARIADIC(arg_info)) {
952
0
        smart_str_appends(&str, "...");
953
0
      }
954
955
4
      smart_str_appendc(&str, '$');
956
4
      smart_str_append(&str, arg_info->name);
957
958
4
      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
4
      if (++i < num_args) {
1030
0
        smart_str_appends(&str, ", ");
1031
0
      }
1032
4
      arg_info++;
1033
4
    }
1034
4
  }
1035
1036
4
  smart_str_appendc(&str, ')');
1037
1038
4
  if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1039
2
    smart_str_appends(&str, ": ");
1040
2
    zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, true);
1041
2
  }
1042
4
  smart_str_0(&str);
1043
1044
4
  return str.s;
1045
4
}
1046
/* }}} */
1047
1048
2
static zend_always_inline zend_string *func_filename(const zend_function *fn) {
1049
2
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
1050
2
}
1051
1052
2
static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
1053
2
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
1054
2
}
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
2
    inheritance_status status) {
1060
2
  zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
1061
2
  zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
1062
2
  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
2
  } else if (status == INHERITANCE_WARNING) {
1075
2
    const zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
1076
2
      child->common.attributes,
1077
2
      "returntypewillchange",
1078
2
      sizeof("returntypewillchange")-1
1079
2
    );
1080
1081
2
    if (!return_type_will_change_attribute) {
1082
2
      zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1083
2
        "Return type of %s should either be compatible with %s, "
1084
2
        "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1085
2
        ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1086
2
      ZEND_ASSERT(!EG(exception));
1087
2
    }
1088
2
  } 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
2
  zend_string_efree(child_prototype);
1094
2
  zend_string_efree(parent_prototype);
1095
2
}
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
579
{
1102
579
  inheritance_status status =
1103
579
    zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1104
579
  if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
1105
2
    if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
1106
0
      add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1107
2
    } else {
1108
2
      ZEND_ASSERT(status == INHERITANCE_ERROR || status == INHERITANCE_WARNING);
1109
2
      emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1110
2
    }
1111
2
  }
1112
579
}
1113
1114
932
#define ZEND_INHERITANCE_LAZY_CHILD_CLONE     (1<<0)
1115
615
#define ZEND_INHERITANCE_CHECK_SILENT         (1<<1) /* don't throw errors */
1116
2.96k
#define ZEND_INHERITANCE_CHECK_PROTO          (1<<2) /* check method prototype (it might be already checked before) */
1117
996
#define ZEND_INHERITANCE_CHECK_VISIBILITY     (1<<3)
1118
862
#define ZEND_INHERITANCE_SET_CHILD_CHANGED    (1<<4)
1119
975
#define ZEND_INHERITANCE_SET_CHILD_PROTO      (1<<5)
1120
976
#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
655
{
1127
655
  uint32_t child_flags;
1128
655
  uint32_t parent_flags = parent->common.fn_flags;
1129
655
  zend_function *proto;
1130
1131
655
#define SEPARATE_METHOD() do { \
1132
556
      if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1133
556
       && 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
556
       && !(child_scope->ce_flags & ZEND_ACC_TRAIT) \
1138
556
       && 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
556
    } while(0)
1146
1147
655
  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
655
  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
655
  child_flags = child->common.fn_flags;
1166
  /* You cannot change from static to non static and vice versa.
1167
   */
1168
655
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1169
652
   && 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
655
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1186
652
   && 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
655
  if ((flags & ZEND_INHERITANCE_SET_CHILD_CHANGED)
1196
153
   && (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
655
  proto = parent->common.prototype ?
1202
603
    parent->common.prototype : parent;
1203
1204
655
  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
58
    if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1208
58
      return INHERITANCE_SUCCESS;
1209
58
    }
1210
0
    parent = proto;
1211
0
  }
1212
1213
597
  if ((flags & ZEND_INHERITANCE_SET_CHILD_PROTO)
1214
580
   && child->common.prototype != proto) {
1215
556
    SEPARATE_METHOD();
1216
556
    child->common.prototype = proto;
1217
556
  }
1218
1219
  /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1220
597
  if ((flags & ZEND_INHERITANCE_CHECK_VISIBILITY)
1221
596
      && (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
597
  if (flags & ZEND_INHERITANCE_CHECK_PROTO) {
1231
596
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1232
17
      return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1233
17
    }
1234
579
    perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1235
579
  }
1236
1237
580
  if ((flags & ZEND_INHERITANCE_RESET_CHILD_OVERRIDE)
1238
580
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1239
0
    SEPARATE_METHOD();
1240
0
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1241
0
  }
1242
1243
580
#undef SEPARATE_METHOD
1244
1245
580
  return INHERITANCE_SUCCESS;
1246
597
}
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
3.07k
{
1251
3.07k
  zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1252
1253
3.07k
  if (child) {
1254
616
    zend_function *func = (zend_function*)Z_PTR_P(child);
1255
1256
616
    if (is_interface && UNEXPECTED(func == parent)) {
1257
      /* The same method in interface may be inherited few times */
1258
0
      return;
1259
0
    }
1260
1261
616
    do_inheritance_check_on_method(
1262
616
      func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1263
2.45k
  } else {
1264
1265
2.45k
    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.45k
    parent = zend_duplicate_function(parent, ce);
1270
1271
2.45k
    if (!is_interface) {
1272
2.41k
      _zend_hash_append_ptr(&ce->function_table, key, parent);
1273
2.41k
    } else {
1274
40
      zend_hash_add_new_ptr(&ce->function_table, key, parent);
1275
40
    }
1276
2.45k
  }
1277
3.07k
}
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
32
) {
1377
32
  zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
1378
32
  zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;
1379
1380
32
  if (child
1381
28
   && (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
32
  if (!parent) {
1387
12
    return;
1388
12
  }
1389
1390
20
  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
20
  child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1408
1409
20
  uint32_t parent_flags = parent->common.fn_flags;
1410
20
  if (parent_flags & ZEND_ACC_PRIVATE) {
1411
0
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1412
0
    return;
1413
0
  }
1414
1415
20
  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
20
  do_inheritance_check_on_method(
1423
20
    child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
1424
20
    ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY
1425
20
      | ZEND_INHERITANCE_SET_CHILD_CHANGED | ZEND_INHERITANCE_SET_CHILD_PROTO
1426
20
      | 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
20
}
1432
1433
16
static prop_variance prop_get_variance(const zend_property_info *prop_info) {
1434
16
  bool unbacked = prop_info->flags & ZEND_ACC_VIRTUAL;
1435
16
  if (unbacked && prop_info->hooks) {
1436
8
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1437
3
      return PROP_COVARIANT;
1438
3
    }
1439
5
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
1440
1
      return PROP_CONTRAVARIANT;
1441
1
    }
1442
5
  }
1443
12
  return PROP_INVARIANT;
1444
16
}
1445
1446
static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1447
694
{
1448
694
  zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1449
1450
694
  if (UNEXPECTED(child)) {
1451
24
    zend_property_info *child_info = Z_PTR_P(child);
1452
24
    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1453
8
      child_info->flags |= ZEND_ACC_CHANGED;
1454
8
    }
1455
24
    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
24
    if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1460
16
      if (!(parent_info->ce->ce_flags & ZEND_ACC_INTERFACE)) {
1461
16
        child_info->prototype = parent_info->prototype;
1462
16
      }
1463
1464
16
      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
16
      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
16
      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
16
      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
16
      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
8
        bool use_child_prop = !parent_info->hooks && child_info->hooks;
1507
1508
8
        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
8
        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
8
        zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1520
8
        if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1521
8
          if (use_child_prop) {
1522
4
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1523
4
          } else {
1524
4
            int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1525
4
            ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1526
4
            ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1527
4
          }
1528
8
        } 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
8
        if (!use_child_prop) {
1538
4
          child_info->offset = parent_info->offset;
1539
4
        }
1540
8
        child_info->flags &= ~ZEND_ACC_VIRTUAL;
1541
8
      }
1542
1543
16
      if (parent_info->hooks || child_info->hooks) {
1544
48
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1545
32
          inherit_property_hook(ce, parent_info, child_info, i);
1546
32
        }
1547
16
      }
1548
1549
16
      prop_variance variance = prop_get_variance(parent_info);
1550
16
      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
16
      } 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
16
      if (child_info->ce == ce) {
1565
16
        child_info->flags &= ~ZEND_ACC_OVERRIDE;
1566
16
      }
1567
16
    }
1568
670
  } else {
1569
670
    zend_function **hooks = parent_info->hooks;
1570
670
    if (hooks) {
1571
5
      ce->num_hooked_props++;
1572
5
      if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1573
0
        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1574
0
      }
1575
5
    }
1576
1577
670
    _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1578
670
  }
1579
694
}
1580
/* }}} */
1581
1582
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1583
621
{
1584
621
  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
621
  ZEND_ASSERT(ce != iface);
1589
621
}
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
198
      if (ce->interfaces[i] == entry) {
1610
56
        break;
1611
56
      }
1612
198
    }
1613
488
    if (i == ce_num) {
1614
432
      ce->interfaces[ce->num_interfaces++] = entry;
1615
432
    }
1616
488
  }
1617
238
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1618
1619
  /* and now call the implementing handlers */
1620
670
  while (ce_num < ce->num_interfaces) {
1621
432
    do_implement_interface(ce, ce->interfaces[ce_num++]);
1622
432
  }
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
178
{
1654
178
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1655
178
  zend_class_constant *c;
1656
1657
178
  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
178
  } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1662
178
    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
178
    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
178
    _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1678
178
  }
1679
178
}
1680
/* }}} */
1681
1682
void zend_build_properties_info_table(zend_class_entry *ce)
1683
1.02k
{
1684
1.02k
  zend_property_info **table, *prop;
1685
1.02k
  size_t size;
1686
1.02k
  if (ce->default_properties_count == 0) {
1687
868
    return;
1688
868
  }
1689
1690
152
  ZEND_ASSERT(ce->properties_info_table == NULL);
1691
152
  size = sizeof(zend_property_info *) * ce->default_properties_count;
1692
152
  if (ce->type == ZEND_USER_CLASS) {
1693
50
    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
152
  memset(table, 0, size);
1700
1701
152
  if (ce->parent && ce->parent->default_properties_count != 0) {
1702
124
    zend_property_info **parent_table = ce->parent->properties_info_table;
1703
124
    memcpy(
1704
124
      table, parent_table,
1705
124
      sizeof(zend_property_info *) * ce->parent->default_properties_count
1706
124
    );
1707
1708
    /* Child did not add any new properties, we are done */
1709
124
    if (ce->default_properties_count == ce->parent->default_properties_count) {
1710
116
      return;
1711
116
    }
1712
124
  }
1713
1714
488
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, prop) {
1715
488
    if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0
1716
184
     && !(prop->flags & ZEND_ACC_VIRTUAL)) {
1717
164
      const zend_property_info *root_prop = prop->prototype;
1718
164
      if (UNEXPECTED(root_prop->flags & ZEND_ACC_VIRTUAL)) {
1719
        /* Prototype is virtual, we need to manually hunt down the first backed property. */
1720
4
        root_prop = prop;
1721
4
        zend_class_entry *parent_ce;
1722
4
        while ((parent_ce = root_prop->ce->parent)) {
1723
4
          zend_property_info *parent_prop = zend_hash_find_ptr(&parent_ce->properties_info, key);
1724
4
          if (!parent_prop
1725
4
           || parent_prop->prototype != prop->prototype
1726
4
           || (parent_prop->flags & ZEND_ACC_VIRTUAL)) {
1727
4
            break;
1728
4
          }
1729
0
          root_prop = parent_prop;
1730
0
        }
1731
4
      }
1732
164
      uint32_t prop_table_offset = OBJ_PROP_TO_NUM(root_prop->offset);
1733
164
      table[prop_table_offset] = prop;
1734
164
    }
1735
488
  } ZEND_HASH_FOREACH_END();
1736
36
}
1737
1738
ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name)
1739
49
{
1740
49
  if (!prop_info->hooks) {
1741
0
    return;
1742
0
  }
1743
49
  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
49
  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
49
  if (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1757
27
   && !ZEND_TYPE_IS_SET(prop_info->type)
1758
26
   && Z_TYPE(ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]) == IS_UNDEF) {
1759
21
    ZVAL_NULL(&ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]);
1760
21
  }
1761
147
  for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1762
98
    const zend_function *func = prop_info->hooks[i];
1763
98
    if (func) {
1764
84
      if ((zend_property_hook_kind)i == ZEND_PROPERTY_HOOK_GET
1765
46
       && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1766
1
       && !(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
84
      if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
1772
0
        abstract_error = false;
1773
0
      }
1774
84
    }
1775
98
  }
1776
49
  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
49
  if ((prop_info->flags & ZEND_ACC_VIRTUAL)
1781
22
   && (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
49
}
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
40
{
1805
40
  ZEND_ASSERT(prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET] == func);
1806
1807
40
  zend_arg_info *value_arg_info = &func->op_array.arg_info[0];
1808
40
  if (!ZEND_TYPE_IS_SET(value_arg_info->type)) {
1809
39
    return INHERITANCE_SUCCESS;
1810
39
  }
1811
1812
1
  if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1813
0
    return INHERITANCE_ERROR;
1814
0
  }
1815
1816
1
  zend_class_entry *ce = prop_info->ce;
1817
1
  return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type);
1818
1
}
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
195
{
1843
195
  zend_property_info *property_info;
1844
195
  zend_string *key;
1845
1846
195
  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
195
  } 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
195
  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
195
  if (ce->parent_name) {
1878
39
    zend_string_release_ex(ce->parent_name, 0);
1879
39
  }
1880
195
  ce->parent = parent_ce;
1881
195
  ce->default_object_handlers = parent_ce->default_object_handlers;
1882
195
  ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1883
1884
  /* Inherit properties */
1885
195
  if (parent_ce->default_properties_count) {
1886
124
    zval *src, *dst, *end;
1887
1888
124
    if (ce->default_properties_count) {
1889
8
      zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1890
8
      src = ce->default_properties_table + ce->default_properties_count;
1891
8
      end = table + parent_ce->default_properties_count;
1892
8
      dst = end + ce->default_properties_count;
1893
8
      ce->default_properties_table = table;
1894
28
      do {
1895
28
        dst--;
1896
28
        src--;
1897
28
        ZVAL_COPY_VALUE_PROP(dst, src);
1898
28
      } while (dst != end);
1899
8
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1900
8
      end = ce->default_properties_table;
1901
116
    } else {
1902
116
      end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1903
116
      dst = end + parent_ce->default_properties_count;
1904
116
      ce->default_properties_table = end;
1905
116
    }
1906
124
    src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1907
124
    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
124
    } else {
1923
675
      do {
1924
675
        dst--;
1925
675
        src--;
1926
675
        ZVAL_COPY_PROP(dst, src);
1927
675
        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
675
        continue;
1932
675
      } while (dst != end);
1933
124
    }
1934
124
    ce->default_properties_count += parent_ce->default_properties_count;
1935
124
  }
1936
1937
195
  if (parent_ce->default_static_members_count) {
1938
3
    zval *src, *dst, *end;
1939
1940
3
    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
3
    } else {
1954
3
      end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1955
3
      dst = end + parent_ce->default_static_members_count;
1956
3
      ce->default_static_members_table = end;
1957
3
    }
1958
3
    src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1959
5
    do {
1960
5
      dst--;
1961
5
      src--;
1962
5
      if (Z_TYPE_P(src) == IS_INDIRECT) {
1963
0
        ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1964
5
      } else {
1965
5
        ZVAL_INDIRECT(dst, src);
1966
5
      }
1967
5
      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
5
    } while (dst != end);
1972
3
    ce->default_static_members_count += parent_ce->default_static_members_count;
1973
3
    if (!ZEND_MAP_PTR(ce->static_members_table)) {
1974
3
      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
3
    }
1979
3
  }
1980
1981
470
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1982
470
    if (property_info->ce == ce) {
1983
40
      if (property_info->flags & ZEND_ACC_STATIC) {
1984
4
        property_info->offset += parent_ce->default_static_members_count;
1985
36
      } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1986
28
        property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1987
28
      }
1988
40
    }
1989
470
  } ZEND_HASH_FOREACH_END();
1990
1991
195
  if (zend_hash_num_elements(&parent_ce->properties_info)) {
1992
124
    zend_hash_extend(&ce->properties_info,
1993
124
      zend_hash_num_elements(&ce->properties_info) +
1994
124
      zend_hash_num_elements(&parent_ce->properties_info), 0);
1995
1996
1.63k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1997
1.63k
      do_inherit_property(property_info, key, ce);
1998
1.63k
    } ZEND_HASH_FOREACH_END();
1999
124
  }
2000
2001
195
  if (ce->num_hooked_props) {
2002
132
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
2003
132
      if (property_info->ce == ce && property_info->hooks) {
2004
30
        zend_verify_hooked_property(ce, property_info, key);
2005
30
      }
2006
132
    } ZEND_HASH_FOREACH_END();
2007
9
  }
2008
2009
195
  if (zend_hash_num_elements(&parent_ce->constants_table)) {
2010
28
    zend_class_constant *c;
2011
2012
28
    zend_hash_extend(&ce->constants_table,
2013
28
      zend_hash_num_elements(&ce->constants_table) +
2014
28
      zend_hash_num_elements(&parent_ce->constants_table), 0);
2015
2016
412
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
2017
412
      do_inherit_class_constant(key, c, ce);
2018
412
    } ZEND_HASH_FOREACH_END();
2019
28
  }
2020
2021
195
  if (zend_hash_num_elements(&parent_ce->function_table)) {
2022
187
    zend_hash_extend(&ce->function_table,
2023
187
      zend_hash_num_elements(&ce->function_table) +
2024
187
      zend_hash_num_elements(&parent_ce->function_table), 0);
2025
187
    uint32_t flags =
2026
187
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2027
187
      ZEND_INHERITANCE_SET_CHILD_CHANGED |
2028
187
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2029
187
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2030
2031
187
    if (!checked) {
2032
171
      flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2033
171
    }
2034
187
    zend_function *func;
2035
5.47k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
2036
5.47k
      do_inherit_method(key, func, ce, false, flags);
2037
5.47k
    } ZEND_HASH_FOREACH_END();
2038
187
  }
2039
2040
195
  do_inherit_parent_constructor(ce);
2041
2042
195
  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
195
  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
195
}
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
189
{
2166
189
  zend_function *func;
2167
189
  zend_string *key;
2168
189
  zend_class_constant *c;
2169
189
  uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2170
2171
189
  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
171
    flags |=
2175
171
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2176
171
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2177
171
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2178
171
  } else {
2179
18
    flags |=
2180
18
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2181
18
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2182
18
  }
2183
2184
490
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2185
490
    do_inherit_iface_constant(key, c, ce, iface);
2186
490
  } ZEND_HASH_FOREACH_END();
2187
2188
1.42k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2189
1.42k
    do_inherit_method(key, func, ce, true, flags);
2190
1.42k
  } ZEND_HASH_FOREACH_END();
2191
2192
189
  zend_hash_extend(&ce->properties_info,
2193
189
    zend_hash_num_elements(&ce->properties_info) +
2194
189
    zend_hash_num_elements(&iface->properties_info), 0);
2195
2196
189
  zend_property_info *prop;
2197
189
  ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2198
189
    do_inherit_property(prop, key, ce);
2199
189
  } ZEND_HASH_FOREACH_END();
2200
2201
189
  do_implement_interface(ce, iface);
2202
189
  if (iface->num_interfaces) {
2203
80
    zend_do_inherit_interfaces(ce, iface);
2204
80
  }
2205
189
}
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
1
{
2252
1
  uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2253
1
  uint32_t num_interfaces = num_parent_interfaces;
2254
1
  zend_string *key;
2255
1
  zend_class_constant *c;
2256
1
  uint32_t i;
2257
2258
2
  for (i = 0; i < ce->num_interfaces; i++) {
2259
1
    zend_class_entry *iface = interfaces[num_parent_interfaces + i];
2260
1
    if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2261
0
      add_dependency_obligation(ce, iface);
2262
0
    }
2263
1
    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
1
    for (uint32_t j = 0; j < num_interfaces; j++) {
2269
0
      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
0
    }
2287
1
    if (iface) {
2288
1
      interfaces[num_interfaces] = iface;
2289
1
      num_interfaces++;
2290
1
    }
2291
1
  }
2292
2293
1
  if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2294
2
    for (i = 0; i < ce->num_interfaces; i++) {
2295
1
      zend_string_release_ex(ce->interface_names[i].name, 0);
2296
1
      zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2297
1
    }
2298
1
    efree(ce->interface_names);
2299
1
  }
2300
2301
1
  ce->num_interfaces = num_interfaces;
2302
1
  ce->interfaces = interfaces;
2303
1
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2304
2305
1
  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
2
  for (; i < num_interfaces; i++) {
2311
1
    do_interface_implementation(ce, ce->interfaces[i]);
2312
1
  }
2313
1
}
2314
/* }}} */
2315
2316
2317
void zend_inheritance_check_override(const zend_class_entry *ce)
2318
864
{
2319
864
  if (ce->ce_flags & ZEND_ACC_TRAIT) {
2320
30
    return;
2321
30
  }
2322
2323
3.87k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *f) {
2324
3.87k
    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
3.87k
  } ZEND_HASH_FOREACH_END();
2333
2334
2.53k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
2335
2.53k
    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
434
    if (prop->hooks) {
2343
162
      for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2344
108
        zend_function *f = prop->hooks[i];
2345
108
        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
108
      }
2354
54
    }
2355
434
  } ZEND_HASH_FOREACH_END();
2356
834
}
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
39
{
2367
39
  zend_function *existing_fn = NULL;
2368
39
  zend_function *new_fn;
2369
2370
39
  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
39
  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
39
  } else {
2410
39
    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2411
39
    memcpy(new_fn, fn, sizeof(zend_op_array));
2412
39
    new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2413
39
  }
2414
39
  new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2415
2416
  /* Reassign method name, in case it is an alias. */
2417
39
  new_fn->common.function_name = name;
2418
39
  function_add_ref(new_fn);
2419
39
  fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2420
39
  zend_add_magic_method(ce, fn, key);
2421
39
}
2422
/* }}} */
2423
2424
static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2425
78
{
2426
78
  if (fn->common.scope->ce_flags & ZEND_ACC_TRAIT) {
2427
2428
39
    fn->common.scope = ce;
2429
2430
39
    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2431
0
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2432
0
    }
2433
39
    if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2434
0
      ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2435
0
    }
2436
39
  }
2437
78
}
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
39
{
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
39
  if (!(original_fn_flags & ZEND_ACC_FINAL)
2447
39
    && (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
39
}
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
26
{
2455
26
  zend_trait_alias  *alias, **alias_ptr;
2456
26
  zend_function      fn_copy;
2457
26
  int                i;
2458
2459
  /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2460
26
  if (ce->trait_aliases) {
2461
13
    alias_ptr = ce->trait_aliases;
2462
13
    alias = *alias_ptr;
2463
13
    i = 0;
2464
26
    while (alias) {
2465
      /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2466
13
      if (alias->alias != NULL
2467
13
        && fn->common.scope == aliases[i]
2468
13
        && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2469
13
      ) {
2470
13
        fn_copy = *fn;
2471
13
        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
13
        } else {
2474
13
          fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2475
13
        }
2476
2477
13
        zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2478
2479
13
        zend_string *lcname = zend_string_tolower(alias->alias);
2480
13
        zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2481
13
        zend_string_release_ex(lcname, 0);
2482
13
      }
2483
13
      alias_ptr++;
2484
13
      alias = *alias_ptr;
2485
13
      i++;
2486
13
    }
2487
13
  }
2488
2489
26
  if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2490
    /* is not in hashtable, thus, function is not to be excluded */
2491
26
    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
26
    if (ce->trait_aliases) {
2495
13
      alias_ptr = ce->trait_aliases;
2496
13
      alias = *alias_ptr;
2497
13
      i = 0;
2498
26
      while (alias) {
2499
        /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2500
13
        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
13
        ) {
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
13
        alias_ptr++;
2511
13
        alias = *alias_ptr;
2512
13
        i++;
2513
13
      }
2514
13
    }
2515
2516
26
    zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2517
2518
26
    zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2519
26
  }
2520
26
}
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
13
{
2525
13
  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
13
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2531
13
    if (traits[i] == trait) {
2532
13
      return i;
2533
13
    }
2534
13
  }
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
13
}
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
26
{
2542
26
  size_t i, j = 0;
2543
26
  zend_trait_precedence *cur_precedence;
2544
26
  zend_trait_method_reference *cur_method_ref;
2545
26
  zend_string *lc_trait_name;
2546
26
  zend_string *lcname;
2547
26
  HashTable **exclude_tables = NULL;
2548
26
  zend_class_entry **aliases = NULL;
2549
26
  zend_class_entry *trait;
2550
2551
  /* resolve class references */
2552
26
  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
26
  if (ce->trait_aliases) {
2622
13
    i = 0;
2623
26
    while (ce->trait_aliases[i]) {
2624
13
      i++;
2625
13
    }
2626
13
    aliases = ecalloc(i, sizeof(zend_class_entry*));
2627
13
    i = 0;
2628
26
    while (ce->trait_aliases[i]) {
2629
13
      const zend_trait_alias *cur_alias = ce->trait_aliases[i];
2630
13
      cur_method_ref = &ce->trait_aliases[i]->trait_method;
2631
13
      lcname = zend_string_tolower(cur_method_ref->method_name);
2632
13
      if (cur_method_ref->class_name) {
2633
        /* For all aliases with an explicit class name, resolve the class now. */
2634
13
        lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2635
13
        trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2636
13
        zend_string_release_ex(lc_trait_name, 0);
2637
13
        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
13
        zend_check_trait_usage(ce, trait, traits);
2641
13
        aliases[i] = trait;
2642
2643
        /* And, ensure that the referenced method is resolvable, too. */
2644
13
        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
13
      } 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
13
      zend_string_release_ex(lcname, 0);
2685
13
      i++;
2686
13
    }
2687
13
  }
2688
2689
26
  *exclude_tables_ptr = exclude_tables;
2690
26
  *aliases_ptr = aliases;
2691
26
}
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
26
{
2696
26
  uint32_t i;
2697
26
  zend_string *key;
2698
26
  zend_function *fn;
2699
2700
26
  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
26
  } else {
2721
52
    for (i = 0; i < ce->num_traits; i++) {
2722
26
      if (traits[i]) {
2723
104
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2724
104
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2725
104
          *contains_abstract_methods |= is_abstract;
2726
104
          if (verify_abstract != is_abstract) {
2727
0
            continue;
2728
0
          }
2729
26
          zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2730
26
        } ZEND_HASH_FOREACH_END();
2731
26
      }
2732
26
    }
2733
26
  }
2734
26
}
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
26
{
2814
52
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2815
26
    zend_string *constant_name;
2816
26
    zend_class_constant *constant;
2817
2818
26
    if (!traits[i]) {
2819
0
      continue;
2820
0
    }
2821
2822
52
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2823
52
      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
52
    } ZEND_HASH_FOREACH_END();
2850
26
  }
2851
26
}
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
26
{
2871
26
  zend_property_info *property_info;
2872
26
  const zend_property_info *colliding_prop;
2873
26
  zend_string* prop_name;
2874
26
  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
52
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2882
26
    if (!traits[i]) {
2883
0
      continue;
2884
0
    }
2885
52
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2886
52
      uint32_t flags = property_info->flags;
2887
2888
      /* next: check for conflicts with current class */
2889
52
      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
26
  }
3004
26
}
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
0
#define zend_update_inherited_handler(handler) do { \
3323
0
    if (ce->handler == (zend_function*)op_array) { \
3324
0
      ce->handler = (zend_function*)new_op_array; \
3325
0
    } \
3326
0
  } while (0)
3327
3328
static zend_op_array *zend_lazy_method_load(
3329
0
    const zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3330
0
  ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3331
0
  ZEND_ASSERT(op_array->scope == pce);
3332
0
  ZEND_ASSERT(op_array->prototype == NULL);
3333
0
  zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3334
0
  memcpy(new_op_array, op_array, sizeof(zend_op_array));
3335
0
  new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3336
0
  new_op_array->scope = ce;
3337
0
  ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3338
0
  ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3339
3340
0
  return new_op_array;
3341
0
}
3342
3343
static zend_class_entry *zend_lazy_class_load(const zend_class_entry *pce)
3344
0
{
3345
0
  zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3346
3347
0
  memcpy(ce, pce, sizeof(zend_class_entry));
3348
0
  ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3349
0
  ce->refcount = 1;
3350
0
  ce->inheritance_cache = NULL;
3351
0
  if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3352
0
    ZEND_MAP_PTR_NEW(ce->mutable_data);
3353
0
  } else {
3354
0
    ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3355
0
  }
3356
3357
  /* properties */
3358
0
  if (ce->default_properties_table) {
3359
0
    zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3360
0
    zval *src = ce->default_properties_table;
3361
0
    const zval *end = src + ce->default_properties_count;
3362
3363
0
    ce->default_properties_table = dst;
3364
0
    for (; src != end; src++, dst++) {
3365
0
      ZVAL_COPY_VALUE_PROP(dst, src);
3366
0
    }
3367
0
  }
3368
3369
  /* methods */
3370
0
  ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3371
0
  if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3372
0
    Bucket *p = emalloc(HT_SIZE(&ce->function_table));
3373
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3374
0
    HT_SET_DATA_ADDR(&ce->function_table, p);
3375
0
    p = ce->function_table.arData;
3376
0
    const Bucket *end = p + ce->function_table.nNumUsed;
3377
0
    for (; p != end; p++) {
3378
0
      zend_op_array *op_array = Z_PTR(p->val);
3379
0
      zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3380
3381
0
      zend_update_inherited_handler(constructor);
3382
0
      zend_update_inherited_handler(destructor);
3383
0
      zend_update_inherited_handler(clone);
3384
0
      zend_update_inherited_handler(__get);
3385
0
      zend_update_inherited_handler(__set);
3386
0
      zend_update_inherited_handler(__call);
3387
0
      zend_update_inherited_handler(__isset);
3388
0
      zend_update_inherited_handler(__unset);
3389
0
      zend_update_inherited_handler(__tostring);
3390
0
      zend_update_inherited_handler(__callstatic);
3391
0
      zend_update_inherited_handler(__debugInfo);
3392
0
      zend_update_inherited_handler(__serialize);
3393
0
      zend_update_inherited_handler(__unserialize);
3394
0
    }
3395
0
  }
3396
3397
  /* static members */
3398
0
  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
0
  ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3409
3410
  /* properties_info */
3411
0
  if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3412
0
    Bucket *p = emalloc(HT_SIZE(&ce->properties_info));
3413
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3414
0
    HT_SET_DATA_ADDR(&ce->properties_info, p);
3415
0
    p = ce->properties_info.arData;
3416
0
    const Bucket *end = p + ce->properties_info.nNumUsed;
3417
0
    for (; p != end; p++) {
3418
0
      zend_property_info *new_prop_info;
3419
3420
0
      const zend_property_info *prop_info = Z_PTR(p->val);
3421
0
      ZEND_ASSERT(prop_info->ce == pce);
3422
0
      ZEND_ASSERT(prop_info->prototype == prop_info);
3423
0
      new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3424
0
      Z_PTR(p->val) = new_prop_info;
3425
0
      memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3426
0
      new_prop_info->ce = ce;
3427
0
      new_prop_info->prototype = new_prop_info;
3428
      /* Deep copy the type information */
3429
0
      zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3430
0
      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
0
    }
3444
0
  }
3445
3446
  /* constants table */
3447
0
  if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3448
0
    Bucket *p = emalloc(HT_SIZE(&ce->constants_table));
3449
0
    memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3450
0
    HT_SET_DATA_ADDR(&ce->constants_table, p);
3451
0
    p = ce->constants_table.arData;
3452
0
    const Bucket *end = p + ce->constants_table.nNumUsed;
3453
0
    for (; p != end; p++) {
3454
0
      zend_class_constant *new_c;
3455
3456
0
      const zend_class_constant *c = Z_PTR(p->val);
3457
0
      ZEND_ASSERT(c->ce == pce);
3458
0
      new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3459
0
      Z_PTR(p->val) = new_c;
3460
0
      memcpy(new_c, c, sizeof(zend_class_constant));
3461
0
      new_c->ce = ce;
3462
0
    }
3463
0
  }
3464
3465
0
  return ce;
3466
0
}
3467
3468
#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
3469
98
# define UPDATE_IS_CACHEABLE(ce) do { \
3470
98
      if ((ce)->type == ZEND_USER_CLASS) { \
3471
95
        is_cacheable &= (ce)->ce_flags; \
3472
95
      } \
3473
98
    } 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
40
{
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
40
  zend_class_entry *parent = NULL;
3487
40
  zend_class_entry **traits_and_interfaces = NULL;
3488
40
  zend_class_entry *proto = NULL;
3489
40
  zend_class_entry *orig_linking_class;
3490
40
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3491
40
  uint32_t i, j;
3492
40
  zval *zv;
3493
40
  ALLOCA_FLAG(use_heap)
3494
3495
40
  SET_ALLOCA_FLAG(use_heap);
3496
40
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3497
3498
40
  if (ce->parent_name) {
3499
13
    parent = zend_fetch_class_by_name(
3500
13
      ce->parent_name, lc_parent_name,
3501
13
      ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3502
13
    if (!parent) {
3503
0
      check_unrecoverable_load_failure(ce);
3504
0
      return NULL;
3505
0
    }
3506
13
    UPDATE_IS_CACHEABLE(parent);
3507
13
  }
3508
3509
40
  if (ce->num_traits || ce->num_interfaces) {
3510
27
    traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3511
3512
53
    for (i = 0; i < ce->num_traits; i++) {
3513
26
      zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3514
26
        ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
3515
26
      if (UNEXPECTED(trait == NULL)) {
3516
0
        free_alloca(traits_and_interfaces, use_heap);
3517
0
        return NULL;
3518
0
      }
3519
26
      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
26
      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
26
      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
26
      traits_and_interfaces[i] = trait;
3539
26
      if (trait) {
3540
26
        UPDATE_IS_CACHEABLE(trait);
3541
26
      }
3542
26
    }
3543
27
  }
3544
3545
40
  if (ce->num_interfaces) {
3546
2
    for (i = 0; i < ce->num_interfaces; i++) {
3547
1
      zend_class_entry *iface = zend_fetch_class_by_name(
3548
1
        ce->interface_names[i].name, ce->interface_names[i].lc_name,
3549
1
        ZEND_FETCH_CLASS_INTERFACE |
3550
1
        ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3551
1
      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
1
      traits_and_interfaces[ce->num_traits + i] = iface;
3557
1
      if (iface) {
3558
1
        UPDATE_IS_CACHEABLE(iface);
3559
1
      }
3560
1
    }
3561
1
  }
3562
3563
40
#ifndef ZEND_WIN32
3564
40
  if (ce->ce_flags & ZEND_ACC_ENUM) {
3565
    /* We will add internal methods. */
3566
1
    is_cacheable = false;
3567
1
  }
3568
40
#endif
3569
3570
40
  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
40
  bool orig_record_errors = EG(record_errors);
3592
40
  if (!orig_record_errors) {
3593
40
    zend_begin_record_errors();
3594
40
  }
3595
3596
40
  zend_try {
3597
40
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3598
      /* Lazy class loading */
3599
0
      ce = zend_lazy_class_load(ce);
3600
0
      zv = zend_hash_find_known_hash(CG(class_table), key);
3601
0
      Z_CE_P(zv) = ce;
3602
40
    } 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
40
    if (CG(unlinked_uses)) {
3611
0
      zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3612
0
    }
3613
3614
40
    orig_linking_class = CG(current_linking_class);
3615
40
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3616
3617
40
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3618
      /* Only register builtin enum methods during inheritance to avoid persisting them in
3619
       * opcache. */
3620
1
      zend_enum_register_funcs(ce);
3621
1
    }
3622
3623
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3624
    zend_link_hooked_object_iter(ce);
3625
#endif
3626
3627
40
    HashTable **trait_exclude_tables;
3628
40
    zend_class_entry **trait_aliases;
3629
40
    bool trait_contains_abstract_methods = false;
3630
40
    if (ce->num_traits) {
3631
26
      zend_traits_init_trait_structures(ce, traits_and_interfaces, &trait_exclude_tables, &trait_aliases);
3632
26
      zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods);
3633
26
      zend_do_traits_constant_binding(ce, traits_and_interfaces);
3634
26
      zend_do_traits_property_binding(ce, traits_and_interfaces);
3635
3636
26
      zend_function *fn;
3637
208
      ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3638
208
        zend_fixup_trait_method(fn, ce);
3639
208
      } ZEND_HASH_FOREACH_END();
3640
26
    }
3641
40
    if (parent) {
3642
13
      if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3643
0
        add_dependency_obligation(ce, parent);
3644
0
      }
3645
13
      zend_do_inheritance(ce, parent);
3646
13
    }
3647
40
    if (ce->num_traits) {
3648
26
      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
26
      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
26
      if (trait_aliases) {
3671
13
        efree(trait_aliases);
3672
13
      }
3673
26
    }
3674
40
    if (ce->num_interfaces) {
3675
      /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3676
1
      uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3677
1
      zend_class_entry **interfaces = emalloc(
3678
1
          sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3679
3680
1
      if (num_parent_interfaces) {
3681
0
        memcpy(interfaces, parent->interfaces,
3682
0
             sizeof(zend_class_entry *) * num_parent_interfaces);
3683
0
      }
3684
1
      memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3685
1
           sizeof(zend_class_entry *) * ce->num_interfaces);
3686
3687
1
      zend_do_implement_interfaces(ce, interfaces);
3688
39
    } else if (parent && parent->num_interfaces) {
3689
0
      zend_do_inherit_interfaces(ce, parent);
3690
0
    }
3691
40
    if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3692
40
      && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3693
40
        ) {
3694
0
      zend_verify_abstract_class(ce);
3695
0
    }
3696
40
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3697
1
      zend_verify_enum(ce);
3698
1
    }
3699
40
    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
40
    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
40
    zend_build_properties_info_table(ce);
3733
40
  } 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
40
  } zend_end_try();
3741
3742
40
  EG(record_errors) = orig_record_errors;
3743
3744
40
  if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3745
40
    zend_inheritance_check_override(ce);
3746
40
    ce->ce_flags |= ZEND_ACC_LINKED;
3747
40
  } 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
40
  if (!CG(current_linking_class)) {
3764
40
    is_cacheable = 0;
3765
40
  }
3766
40
  CG(current_linking_class) = orig_linking_class;
3767
3768
40
  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
40
  if (!orig_record_errors) {
3786
40
    zend_emit_recorded_errors();
3787
40
    zend_free_recorded_errors();
3788
40
  }
3789
40
  if (traits_and_interfaces) {
3790
27
    free_alloca(traits_and_interfaces, use_heap);
3791
27
  }
3792
3793
40
  if (ZSTR_HAS_CE_CACHE(ce->name)) {
3794
0
    ZSTR_SET_CE_CACHE(ce->name, ce);
3795
0
  }
3796
3797
40
  return ce;
3798
40
}
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
58
{
3804
58
  zend_string *key;
3805
58
  zend_function *parent_func;
3806
58
  const zend_property_info *parent_info;
3807
58
  const zend_class_constant *parent_const;
3808
58
  inheritance_status overall_status = INHERITANCE_SUCCESS;
3809
3810
448
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3811
448
    zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3812
448
    if (zv) {
3813
19
      zend_function *child_func = Z_FUNC_P(zv);
3814
19
      inheritance_status status =
3815
19
        do_inheritance_check_on_method(
3816
19
          child_func, child_func->common.scope,
3817
19
          parent_func, parent_func->common.scope,
3818
19
          ce, NULL,
3819
19
          ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3820
19
      if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3821
2
        overall_status = INHERITANCE_WARNING;
3822
17
      } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3823
11
        return status;
3824
11
      }
3825
19
    }
3826
448
  } ZEND_HASH_FOREACH_END();
3827
3828
230
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3829
230
    const zval *zv;
3830
230
    if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3831
67
      continue;
3832
67
    }
3833
3834
1
    zv = zend_hash_find_known_hash(&ce->properties_info, key);
3835
1
    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
1
  } ZEND_HASH_FOREACH_END();
3845
3846
150
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3847
150
    const zval *zv;
3848
150
    if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3849
0
      continue;
3850
0
    }
3851
3852
28
    zv = zend_hash_find_known_hash(&ce->constants_table, key);
3853
28
    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
28
  } ZEND_HASH_FOREACH_END();
3864
3865
47
  return overall_status;
3866
47
}
3867
/* }}} */
3868
3869
47
static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3870
47
  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
47
  if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3888
26
    return true;
3889
26
  }
3890
21
  return false;
3891
47
}
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
58
{
3895
58
  inheritance_status status;
3896
58
  zend_class_entry *proto = NULL;
3897
58
  zend_class_entry *orig_linking_class;
3898
3899
58
  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
58
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3909
58
  UPDATE_IS_CACHEABLE(parent_ce);
3910
58
  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
58
  orig_linking_class = CG(current_linking_class);
3927
58
  CG(current_linking_class) = NULL;
3928
58
  status = zend_can_early_bind(ce, parent_ce);
3929
58
  CG(current_linking_class) = orig_linking_class;
3930
58
  if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3931
47
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3932
      /* Lazy class loading */
3933
0
      ce = zend_lazy_class_load(ce);
3934
47
    } 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
47
    if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3941
21
      return NULL;
3942
21
    }
3943
3944
26
    orig_linking_class = CG(current_linking_class);
3945
26
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3946
3947
26
    bool orig_record_errors = EG(record_errors);
3948
3949
26
    zend_try{
3950
26
      CG(zend_lineno) = ce->info.user.line_start;
3951
3952
26
      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
26
      zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3961
26
      if (parent_ce && parent_ce->num_interfaces) {
3962
2
        zend_do_inherit_interfaces(ce, parent_ce);
3963
2
      }
3964
26
      zend_build_properties_info_table(ce);
3965
26
      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
26
      zend_inheritance_check_override(ce);
3969
26
      ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3970
26
      ce->ce_flags |= ZEND_ACC_LINKED;
3971
3972
26
      CG(current_linking_class) = orig_linking_class;
3973
26
    } 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
26
    } zend_end_try();
3980
3981
26
    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
26
    if (!orig_record_errors) {
3999
0
      zend_emit_recorded_errors();
4000
0
      zend_free_recorded_errors();
4001
0
    }
4002
4003
26
    if (ZSTR_HAS_CE_CACHE(ce->name)) {
4004
0
      ZSTR_SET_CE_CACHE(ce->name, ce);
4005
0
    }
4006
26
    zend_observer_class_linked_notify(ce, lcname);
4007
4008
26
    return ce;
4009
26
  }
4010
11
  return NULL;
4011
58
}
4012
/* }}} */