Coverage Report

Created: 2025-12-14 06:05

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