Coverage Report

Created: 2025-12-14 06:09

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
30
) {
74
30
  const zend_type_list *const old_list = ZEND_TYPE_LIST(*parent_type);
75
30
  size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
76
30
  zend_type_list *new_list = use_arena
77
30
    ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
78
79
30
  memcpy(new_list, old_list, size);
80
30
  ZEND_TYPE_SET_LIST(*parent_type, new_list);
81
30
  if (use_arena) {
82
30
    ZEND_TYPE_FULL_MASK(*parent_type) |= _ZEND_TYPE_ARENA_BIT;
83
30
  }
84
85
30
  zend_type *list_type;
86
96
  ZEND_TYPE_LIST_FOREACH_MUTABLE(new_list, list_type) {
87
96
    zend_type_copy_ctor(list_type, use_arena, persistent);
88
96
  } ZEND_TYPE_LIST_FOREACH_END();
89
30
}
90
91
1.46k
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
92
1.46k
  if (ZEND_TYPE_HAS_LIST(*type)) {
93
30
    zend_type_list_copy_ctor(type, use_arena, persistent);
94
1.43k
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
95
96
    zend_string_addref(ZEND_TYPE_NAME(*type));
96
96
  }
97
1.46k
}
98
99
static zend_function *zend_duplicate_internal_function(const zend_function *func, const zend_class_entry *ce) /* {{{ */
100
4.67k
{
101
4.67k
  zend_function *new_function;
102
103
4.67k
  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.34k
  } else {
107
2.34k
    new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
108
2.34k
    memcpy(new_function, func, sizeof(zend_internal_function));
109
2.34k
    new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
110
2.34k
  }
111
4.67k
  if (EXPECTED(new_function->common.function_name)) {
112
4.67k
    zend_string_addref(new_function->common.function_name);
113
4.67k
  }
114
4.67k
  return new_function;
115
4.67k
}
116
/* }}} */
117
118
static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
119
5.83k
{
120
5.83k
  if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
121
4.67k
    return zend_duplicate_internal_function(func, ce);
122
4.67k
  } else {
123
1.16k
    if (func->op_array.refcount) {
124
893
      (*func->op_array.refcount)++;
125
893
    }
126
1.16k
    if (EXPECTED(func->op_array.function_name)) {
127
1.16k
      zend_string_addref(func->op_array.function_name);
128
1.16k
    }
129
1.16k
    return func;
130
1.16k
  }
131
5.83k
}
132
/* }}} */
133
134
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
135
2.09k
{
136
2.09k
  zend_class_entry *parent = ce->parent;
137
138
2.09k
  ZEND_ASSERT(parent != NULL);
139
140
  /* You cannot change create_object */
141
2.09k
  ce->create_object = parent->create_object;
142
143
  /* Inherit special functions if needed */
144
2.09k
  if (EXPECTED(!ce->get_iterator)) {
145
1.95k
    ce->get_iterator = parent->get_iterator;
146
1.95k
  }
147
2.09k
  if (EXPECTED(!ce->__get)) {
148
2.06k
    ce->__get = parent->__get;
149
2.06k
  }
150
2.09k
  if (EXPECTED(!ce->__set)) {
151
2.08k
    ce->__set = parent->__set;
152
2.08k
  }
153
2.09k
  if (EXPECTED(!ce->__unset)) {
154
2.09k
    ce->__unset = parent->__unset;
155
2.09k
  }
156
2.09k
  if (EXPECTED(!ce->__isset)) {
157
2.08k
    ce->__isset = parent->__isset;
158
2.08k
  }
159
2.09k
  if (EXPECTED(!ce->__call)) {
160
2.08k
    ce->__call = parent->__call;
161
2.08k
  }
162
2.09k
  if (EXPECTED(!ce->__callstatic)) {
163
2.08k
    ce->__callstatic = parent->__callstatic;
164
2.08k
  }
165
2.09k
  if (EXPECTED(!ce->__tostring)) {
166
2.07k
    ce->__tostring = parent->__tostring;
167
2.07k
  }
168
2.09k
  if (EXPECTED(!ce->clone)) {
169
2.09k
    ce->clone = parent->clone;
170
2.09k
  }
171
2.09k
  if (EXPECTED(!ce->__serialize)) {
172
2.09k
    ce->__serialize = parent->__serialize;
173
2.09k
  }
174
2.09k
  if (EXPECTED(!ce->__unserialize)) {
175
2.09k
    ce->__unserialize = parent->__unserialize;
176
2.09k
  }
177
2.09k
  if (EXPECTED(!ce->serialize)) {
178
2.09k
    ce->serialize = parent->serialize;
179
2.09k
  }
180
2.09k
  if (EXPECTED(!ce->unserialize)) {
181
2.09k
    ce->unserialize = parent->unserialize;
182
2.09k
  }
183
2.09k
  if (!ce->destructor) {
184
2.07k
    ce->destructor = parent->destructor;
185
2.07k
  }
186
2.09k
  if (EXPECTED(!ce->__debugInfo)) {
187
2.09k
    ce->__debugInfo = parent->__debugInfo;
188
2.09k
  }
189
190
2.09k
  if (ce->constructor) {
191
255
    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
255
    return;
197
255
  }
198
199
1.84k
  ce->constructor = parent->constructor;
200
1.84k
}
201
/* }}} */
202
203
const char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
204
102
{
205
102
  if (fn_flags & ZEND_ACC_PUBLIC) {
206
12
    return "public";
207
90
  } else if (fn_flags & ZEND_ACC_PRIVATE) {
208
64
    return "private";
209
64
  } else {
210
26
    ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
211
26
    return "protected";
212
26
  }
213
102
}
214
/* }}} */
215
216
static const char *zend_asymmetric_visibility_string(uint32_t fn_flags) /* {{{ */
217
8
{
218
8
  if (fn_flags & ZEND_ACC_PRIVATE_SET) {
219
0
    return "private(set)";
220
8
  } else if (fn_flags & ZEND_ACC_PROTECTED_SET) {
221
2
    return "protected(set)";
222
6
  } else {
223
6
    ZEND_ASSERT(!(fn_flags & ZEND_ACC_PUBLIC_SET));
224
6
    return "omitted";
225
6
  }
226
8
}
227
228
5.20k
static zend_string *resolve_class_name(const zend_class_entry *scope, zend_string *name) {
229
5.20k
  ZEND_ASSERT(scope);
230
5.20k
  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
5.20k
  } else if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_SELF))) {
237
14
    return scope->name;
238
5.18k
  } else {
239
5.18k
    return name;
240
5.18k
  }
241
5.20k
}
242
243
1.12k
static bool class_visible(const zend_class_entry *ce) {
244
1.12k
  if (ce->type == ZEND_INTERNAL_CLASS) {
245
122
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
246
998
  } else {
247
998
    ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
248
998
    return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
249
648
      || ce->info.user.filename == CG(compiled_filename);
250
998
  }
251
1.12k
}
252
253
330
static zend_always_inline void register_unresolved_class(zend_string *name) {
254
  /* We'll autoload this class and process delayed variance obligations later. */
255
330
  if (!CG(delayed_autoloads)) {
256
94
    ALLOC_HASHTABLE(CG(delayed_autoloads));
257
94
    zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
258
94
  }
259
330
  zend_hash_add_empty_element(CG(delayed_autoloads), name);
260
330
}
261
262
static zend_class_entry *lookup_class_ex(
263
4.44k
    zend_class_entry *scope, zend_string *name, bool register_unresolved) {
264
4.44k
  zend_class_entry *ce;
265
4.44k
  bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
266
267
4.44k
  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
4.39k
  ce = zend_lookup_class_ex(
284
4.39k
      name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
285
286
4.39k
  if (!CG(in_compilation) || in_preload) {
287
2.12k
    if (ce) {
288
1.22k
      return ce;
289
1.22k
    }
290
291
900
    if (register_unresolved) {
292
330
      register_unresolved_class(name);
293
330
    }
294
2.27k
  } else {
295
2.27k
    if (ce && class_visible(ce)) {
296
1.12k
      return ce;
297
1.12k
    }
298
299
    /* The current class may not be registered yet, so check for it explicitly. */
300
1.15k
    if (zend_string_equals_ci(scope->name, name)) {
301
26
      return scope;
302
26
    }
303
1.15k
  }
304
305
2.02k
  return NULL;
306
4.39k
}
307
308
3.14k
static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name) {
309
3.14k
  return lookup_class_ex(scope, name, /* register_unresolved */ false);
310
3.14k
}
311
312
/* Instanceof that's safe to use on unlinked classes. */
313
700
static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) {
314
700
  if (ce1 == ce2) {
315
72
    return true;
316
72
  }
317
318
628
  if (ce1->ce_flags & ZEND_ACC_LINKED) {
319
564
    return instanceof_function(ce1, ce2);
320
564
  }
321
322
64
  if (ce1->parent) {
323
60
    zend_class_entry *parent_ce;
324
60
    if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
325
38
      parent_ce = ce1->parent;
326
38
    } else {
327
22
      parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
328
22
        ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
329
22
    }
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
60
    if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
334
46
      return true;
335
46
    }
336
60
  }
337
338
18
  if (ce1->num_interfaces) {
339
12
    uint32_t i;
340
12
    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
4
      for (i = 0; i < ce1->num_interfaces; i++) {
344
4
        if (unlinked_instanceof(ce1->interfaces[i], ce2)) {
345
4
          return true;
346
4
        }
347
4
      }
348
8
    } else {
349
12
      for (i = 0; i < ce1->num_interfaces; i++) {
350
10
        const zend_class_entry *ce = zend_lookup_class_ex(
351
10
          ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
352
10
          ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
353
        /* Avoid recursing if class implements itself. */
354
10
        if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
355
6
          return true;
356
6
        }
357
10
      }
358
8
    }
359
12
  }
360
361
8
  return false;
362
18
}
363
364
static bool zend_type_permits_self(
365
24
    const zend_type type, const zend_class_entry *scope, zend_class_entry *self) {
366
24
  if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
367
6
    return true;
368
6
  }
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
18
  const zend_type *single_type;
374
48
  ZEND_TYPE_FOREACH(type, single_type) {
375
48
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
376
30
      zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
377
30
      const zend_class_entry *ce = lookup_class(self, name);
378
30
      if (ce && unlinked_instanceof(self, ce)) {
379
18
        return true;
380
18
      }
381
30
    }
382
48
  } ZEND_TYPE_FOREACH_END();
383
0
  return false;
384
18
}
385
386
static void track_class_dependency(zend_class_entry *ce, zend_string *class_name)
387
678
{
388
678
  HashTable *ht;
389
390
678
  ZEND_ASSERT(class_name);
391
678
  if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
392
202
    return;
393
476
  } else if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_SELF))
394
476
          || zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_PARENT))) {
395
0
    return;
396
0
  }
397
398
476
#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
476
  if (ce->type == ZEND_INTERNAL_CLASS) {
402
70
    return;
403
70
  }
404
406
#endif
405
406
406
  ht = (HashTable*)CG(current_linking_class)->inheritance_cache;
407
408
406
  if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
409
    // TODO: dependency on not-immutable class ???
410
18
    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
18
    CG(current_linking_class)->ce_flags &= ~ZEND_ACC_CACHEABLE;
416
18
    CG(current_linking_class) = NULL;
417
18
    return;
418
18
  }
419
420
  /* Record dependency */
421
388
  if (!ht) {
422
68
    ALLOC_HASHTABLE(ht);
423
68
    zend_hash_init(ht, 0, NULL, NULL, 0);
424
68
    CG(current_linking_class)->inheritance_cache = (zend_inheritance_cache_entry*)ht;
425
68
  }
426
388
  zend_hash_add_ptr(ht, class_name, ce);
427
388
}
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
514
{
434
514
  ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(fe_type));
435
514
  bool have_unresolved = false;
436
514
  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
1.43k
  ZEND_TYPE_FOREACH(fe_type, single_type) {
441
1.43k
    zend_class_entry *fe_ce;
442
1.43k
    zend_string *fe_class_name = NULL;
443
1.43k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
444
916
      fe_class_name =
445
916
        resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
446
916
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
447
278
        return INHERITANCE_SUCCESS;
448
278
      }
449
450
638
      if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
451
638
      fe_ce = lookup_class(fe_scope, fe_class_name);
452
638
    } 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
638
    if (!fe_ce || !proto_ce) {
460
442
      have_unresolved = true;
461
442
      continue;
462
442
    }
463
196
    if (unlinked_instanceof(fe_ce, proto_ce)) {
464
4
      track_class_dependency(fe_ce, fe_class_name);
465
4
      track_class_dependency(proto_ce, proto_class_name);
466
4
      return INHERITANCE_SUCCESS;
467
4
    }
468
196
  } ZEND_TYPE_FOREACH_END();
469
470
232
  return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
471
514
}
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
1.20k
    zend_class_entry *proto_scope, const zend_type proto_type) {
477
1.20k
  zend_class_entry *fe_ce = NULL;
478
1.20k
  bool have_unresolved = false;
479
480
  /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
481
1.20k
  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
72
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
486
72
    if (!fe_ce) {
487
48
      have_unresolved = true;
488
48
    } else {
489
24
      track_class_dependency(fe_ce, fe_class_name);
490
24
      return INHERITANCE_SUCCESS;
491
24
    }
492
72
  }
493
494
  /* If the parent has 'callable' as a return type, then Closure satisfies the co-variant check */
495
1.18k
  if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_CALLABLE) {
496
6
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
497
6
    if (!fe_ce) {
498
0
      have_unresolved = true;
499
6
    } else if (fe_ce == zend_ce_closure) {
500
4
      track_class_dependency(fe_ce, fe_class_name);
501
4
      return INHERITANCE_SUCCESS;
502
4
    }
503
6
  }
504
505
  /* If the parent has 'static' as a return type, then final classes could replace it with self */
506
1.17k
  if ((ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_STATIC) && (fe_scope->ce_flags & ZEND_ACC_FINAL)) {
507
32
    if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
508
32
    if (!fe_ce) {
509
0
      have_unresolved = true;
510
32
    } else if (fe_ce == fe_scope) {
511
24
      track_class_dependency(fe_ce, fe_class_name);
512
24
      return INHERITANCE_SUCCESS;
513
24
    }
514
32
  }
515
516
1.15k
  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
1.15k
  bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
521
2.69k
  ZEND_TYPE_FOREACH(proto_type, single_type) {
522
2.69k
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
523
126
      inheritance_status subtype_status = zend_is_class_subtype_of_type(
524
126
        fe_scope, fe_class_name, proto_scope, *single_type);
525
526
126
      switch (subtype_status) {
527
32
        case INHERITANCE_ERROR:
528
32
          if (is_intersection) {
529
0
            return INHERITANCE_ERROR;
530
0
          }
531
32
          continue;
532
58
        case INHERITANCE_UNRESOLVED:
533
58
          have_unresolved = true;
534
58
          continue;
535
36
        case INHERITANCE_SUCCESS:
536
36
          if (!is_intersection) {
537
36
            return INHERITANCE_SUCCESS;
538
36
          }
539
0
          continue;
540
0
        EMPTY_SWITCH_DEFAULT_CASE();
541
126
      }
542
126
    }
543
544
1.41k
    zend_class_entry *proto_ce;
545
1.41k
    zend_string *proto_class_name = NULL;
546
1.41k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
547
1.34k
      proto_class_name =
548
1.34k
        resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
549
1.34k
      if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
550
402
        if (!is_intersection) {
551
386
          return INHERITANCE_SUCCESS;
552
386
        }
553
16
        continue;
554
402
      }
555
556
940
      if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
557
940
      proto_ce = lookup_class(proto_scope, proto_class_name);
558
940
    } else {
559
      /* standard type */
560
76
      ZEND_ASSERT(!is_intersection);
561
76
      continue;
562
76
    }
563
564
940
    if (!fe_ce || !proto_ce) {
565
520
      have_unresolved = true;
566
520
      continue;
567
520
    }
568
420
    if (unlinked_instanceof(fe_ce, proto_ce)) {
569
306
      track_class_dependency(fe_ce, fe_class_name);
570
306
      track_class_dependency(proto_ce, proto_class_name);
571
306
      if (!is_intersection) {
572
164
        return INHERITANCE_SUCCESS;
573
164
      }
574
306
    } else {
575
114
      if (is_intersection) {
576
36
        return INHERITANCE_ERROR;
577
36
      }
578
114
    }
579
420
  } ZEND_TYPE_FOREACH_END();
580
581
532
  if (have_unresolved) {
582
382
    return INHERITANCE_UNRESOLVED;
583
382
  }
584
150
  return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
585
532
}
586
587
5.06k
static zend_string *get_class_from_type(const zend_class_entry *scope, const zend_type single_type) {
588
5.06k
  if (ZEND_TYPE_HAS_NAME(single_type)) {
589
1.62k
    return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
590
1.62k
  }
591
3.44k
  return NULL;
592
5.06k
}
593
594
1.00k
static void register_unresolved_classes(zend_class_entry *scope, const zend_type type) {
595
1.00k
  const zend_type *single_type;
596
2.45k
  ZEND_TYPE_FOREACH(type, single_type) {
597
2.45k
    if (ZEND_TYPE_HAS_LIST(*single_type)) {
598
108
      register_unresolved_classes(scope, *single_type);
599
108
      continue;
600
108
    }
601
1.34k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
602
1.29k
      zend_string *class_name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
603
1.29k
      lookup_class_ex(scope, class_name, /* register_unresolved */ true);
604
1.29k
    }
605
1.34k
  } ZEND_TYPE_FOREACH_END();
606
1.00k
}
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
376
{
612
376
  bool have_unresolved = false;
613
376
  const zend_type *single_type;
614
376
  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
376
  if (proto_type_mask & MAY_BE_OBJECT) {
621
42
    ZEND_TYPE_FOREACH(fe_type, single_type) {
622
42
      zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
623
42
      if (!fe_class_name) {
624
0
        continue;
625
0
      }
626
28
      zend_class_entry *fe_ce = lookup_class(fe_scope, fe_class_name);
627
28
      if (fe_ce) {
628
6
        track_class_dependency(fe_ce, fe_class_name);
629
6
        return INHERITANCE_SUCCESS;
630
22
      } else {
631
22
        have_unresolved = true;
632
22
      }
633
28
    } ZEND_TYPE_FOREACH_END();
634
14
  }
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
370
  inheritance_status early_exit_status =
641
370
    ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
642
958
  ZEND_TYPE_FOREACH(proto_type, single_type) {
643
958
    inheritance_status status;
644
645
958
    if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
646
62
      status = zend_is_intersection_subtype_of_type(
647
62
        fe_scope, fe_type, proto_scope, *single_type);
648
526
    } else {
649
526
      zend_string *proto_class_name = get_class_from_type(proto_scope, *single_type);
650
526
      if (!proto_class_name) {
651
12
        continue;
652
12
      }
653
654
514
      zend_class_entry *proto_ce = NULL;
655
514
      status = zend_is_intersection_subtype_of_class(
656
514
        fe_scope, fe_type, proto_scope, proto_class_name, proto_ce);
657
514
    }
658
659
576
    if (status == early_exit_status) {
660
108
      return status;
661
108
    }
662
468
    if (status == INHERITANCE_UNRESOLVED) {
663
220
      have_unresolved = true;
664
220
    }
665
468
  } ZEND_TYPE_FOREACH_END();
666
667
262
  if (have_unresolved) {
668
178
    return INHERITANCE_UNRESOLVED;
669
178
  }
670
671
84
  return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
672
262
}
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
5.21k
{
678
5.21k
  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
5.21k
  if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
683
469
      !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
684
465
    return INHERITANCE_SUCCESS;
685
465
  }
686
687
  /* Builtin types may be removed, but not added */
688
4.74k
  uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
689
4.74k
  uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
690
4.74k
  uint32_t added_types = fe_type_mask & ~proto_type_mask;
691
4.74k
  if (added_types) {
692
166
    if ((added_types & MAY_BE_STATIC)
693
24
        && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
694
      /* Replacing type that accepts self with static is okay */
695
24
      added_types &= ~MAY_BE_STATIC;
696
24
    }
697
698
166
    if (added_types == MAY_BE_NEVER) {
699
      /* never is the bottom type */
700
6
      return INHERITANCE_SUCCESS;
701
6
    }
702
703
160
    if (added_types) {
704
      /* Otherwise adding new types is illegal */
705
136
      return INHERITANCE_ERROR;
706
136
    }
707
160
  }
708
709
4.60k
  inheritance_status early_exit_status;
710
4.60k
  bool have_unresolved = false;
711
712
4.60k
  if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
713
184
    early_exit_status =
714
184
      ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
715
184
    inheritance_status status = zend_is_intersection_subtype_of_type(
716
184
      fe_scope, fe_type, proto_scope, proto_type);
717
718
184
    if (status == early_exit_status) {
719
50
      return status;
720
50
    }
721
134
    if (status == INHERITANCE_UNRESOLVED) {
722
82
      have_unresolved = true;
723
82
    }
724
4.42k
  } 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
4.42k
    early_exit_status = INHERITANCE_ERROR;
730
4.42k
    const zend_type *single_type;
731
9.06k
    ZEND_TYPE_FOREACH(fe_type, single_type) {
732
9.06k
      inheritance_status status;
733
      /* Union has an intersection type as it's member */
734
9.06k
      if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
735
130
        status = zend_is_intersection_subtype_of_type(
736
130
          fe_scope, *single_type, proto_scope, proto_type);
737
4.51k
      } else {
738
4.51k
        zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
739
4.51k
        if (!fe_class_name) {
740
3.43k
          continue;
741
3.43k
        }
742
743
1.08k
        status = zend_is_class_subtype_of_type(
744
1.08k
          fe_scope, fe_class_name, proto_scope, proto_type);
745
1.08k
      }
746
747
1.21k
      if (status == early_exit_status) {
748
92
        return status;
749
92
      }
750
1.11k
      if (status == INHERITANCE_UNRESOLVED) {
751
388
        have_unresolved = true;
752
388
      }
753
1.11k
    } ZEND_TYPE_FOREACH_END();
754
4.42k
  }
755
756
4.46k
  if (!have_unresolved) {
757
4.01k
    return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
758
4.01k
  }
759
760
448
  register_unresolved_classes(fe_scope, fe_type);
761
448
  register_unresolved_classes(proto_scope, proto_type);
762
448
  return INHERITANCE_UNRESOLVED;
763
4.46k
}
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
2.17k
{
769
2.17k
  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
1.18k
    return INHERITANCE_SUCCESS;
772
1.18k
  }
773
774
986
  if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
775
    /* Child defines a type, but parent doesn't, violates LSP */
776
12
    return INHERITANCE_ERROR;
777
12
  }
778
779
  /* Contravariant type check is performed as a covariant type check with swapped
780
   * argument order. */
781
974
  return zend_perform_covariant_type_check(
782
974
    proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
783
986
}
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
4.46k
{
793
4.46k
  uint32_t num_args, proto_num_args, fe_num_args;
794
4.46k
  inheritance_status status, local_status;
795
4.46k
  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
4.46k
  ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
801
4.46k
    && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
802
4.46k
      && (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
4.46k
  ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
807
4.46k
      || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
808
809
  /* The number of required arguments cannot increase. */
810
4.46k
  if (proto->common.required_num_args < fe->common.required_num_args) {
811
18
    return INHERITANCE_ERROR;
812
18
  }
813
814
  /* by-ref constraints on return values are covariant */
815
4.44k
  if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
816
32
    && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
817
6
    return INHERITANCE_ERROR;
818
6
  }
819
820
4.44k
  proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
821
4.44k
  fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
822
823
  /* A variadic function cannot become non-variadic */
824
4.44k
  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
4.44k
  proto_num_args = proto->common.num_args + proto_is_variadic;
830
4.44k
  fe_num_args = fe->common.num_args + fe_is_variadic;
831
4.44k
  num_args = MAX(proto_num_args, fe_num_args);
832
833
4.44k
  status = INHERITANCE_SUCCESS;
834
6.55k
  for (uint32_t i = 0; i < num_args; i++) {
835
2.26k
    zend_arg_info *proto_arg_info =
836
2.26k
      i < proto_num_args ? &proto->common.arg_info[i] :
837
2.26k
      proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
838
2.26k
    zend_arg_info *fe_arg_info =
839
2.26k
      i < fe_num_args ? &fe->common.arg_info[i] :
840
2.26k
      fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
841
2.26k
    if (!proto_arg_info) {
842
      /* A new (optional) argument has been added, which is fine. */
843
23
      continue;
844
23
    }
845
2.23k
    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
66
      return INHERITANCE_ERROR;
850
66
    }
851
852
2.17k
    local_status = zend_do_perform_arg_type_hint_check(
853
2.17k
      fe_scope, fe_arg_info, proto_scope, proto_arg_info);
854
855
2.17k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
856
132
      if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
857
80
        return INHERITANCE_ERROR;
858
80
      }
859
52
      ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
860
52
      status = INHERITANCE_UNRESOLVED;
861
52
    }
862
863
    /* by-ref constraints on arguments are invariant */
864
2.09k
    if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
865
8
      return INHERITANCE_ERROR;
866
8
    }
867
2.09k
  }
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
4.28k
  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
3.58k
    if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
874
42
      if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
875
10
        return INHERITANCE_ERROR;
876
10
      }
877
32
      if (status == INHERITANCE_SUCCESS) {
878
32
        return INHERITANCE_WARNING;
879
32
      }
880
0
      return status;
881
32
    }
882
883
3.54k
    local_status = zend_perform_covariant_type_check(
884
3.54k
      fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
885
886
3.54k
    if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
887
282
      if (local_status == INHERITANCE_ERROR
888
94
          && ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
889
14
        local_status = INHERITANCE_WARNING;
890
14
      }
891
282
      return local_status;
892
282
    }
893
3.54k
  }
894
895
3.96k
  return status;
896
4.28k
}
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
674
{
902
674
  if (ZEND_TYPE_IS_SET(arg_info->type)) {
903
516
    zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
904
516
    smart_str_append(str, type_str);
905
516
    zend_string_release(type_str);
906
516
    if (!return_hint) {
907
232
      smart_str_appendc(str, ' ');
908
232
    }
909
516
  }
910
674
}
911
/* }}} */
912
913
static ZEND_COLD zend_string *zend_get_function_declaration(
914
    const zend_function *fptr, zend_class_entry *scope) /* {{{ */
915
476
{
916
476
  smart_str str = {0};
917
918
476
  if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
919
12
    smart_str_appendc(&str, '&');
920
12
  }
921
922
476
  if (fptr->common.scope) {
923
476
    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
476
    } else {
927
476
      smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), ZSTR_LEN(fptr->common.scope->name));
928
476
    }
929
476
    smart_str_appends(&str, "::");
930
476
  }
931
932
476
  smart_str_append(&str, fptr->common.function_name);
933
476
  smart_str_appendc(&str, '(');
934
935
476
  if (fptr->common.arg_info) {
936
428
    uint32_t num_args, required;
937
428
    zend_arg_info *arg_info = fptr->common.arg_info;
938
939
428
    required = fptr->common.required_num_args;
940
428
    num_args = fptr->common.num_args;
941
428
    if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
942
10
      num_args++;
943
10
    }
944
818
    for (uint32_t i = 0; i < num_args;) {
945
390
      zend_append_type_hint(&str, scope, arg_info, false);
946
947
390
      if (ZEND_ARG_SEND_MODE(arg_info)) {
948
10
        smart_str_appendc(&str, '&');
949
10
      }
950
951
390
      if (ZEND_ARG_IS_VARIADIC(arg_info)) {
952
10
        smart_str_appends(&str, "...");
953
10
      }
954
955
390
      smart_str_appendc(&str, '$');
956
390
      if (fptr->type == ZEND_INTERNAL_FUNCTION) {
957
70
        smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
958
320
      } else {
959
320
        smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name));
960
320
      }
961
962
390
      if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
963
122
        smart_str_appends(&str, " = ");
964
965
122
        if (fptr->type == ZEND_INTERNAL_FUNCTION) {
966
28
          if (((zend_internal_arg_info*)arg_info)->default_value) {
967
28
            smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->default_value);
968
28
          } else {
969
0
            smart_str_appends(&str, "<default>");
970
0
          }
971
94
        } else {
972
94
          zend_op *precv = NULL;
973
94
          {
974
94
            uint32_t idx  = i;
975
94
            zend_op *op = fptr->op_array.opcodes;
976
94
            const zend_op *end = op + fptr->op_array.last;
977
978
94
            ++idx;
979
494
            while (op < end) {
980
400
              if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
981
272
                  && op->op1.num == (zend_ulong)idx)
982
94
              {
983
94
                precv = op;
984
94
              }
985
400
              ++op;
986
400
            }
987
94
          }
988
94
          if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
989
94
            zval *zv = RT_CONSTANT(precv, precv->op2);
990
991
94
            if (Z_TYPE_P(zv) == IS_FALSE) {
992
2
              smart_str_appends(&str, "false");
993
92
            } else if (Z_TYPE_P(zv) == IS_TRUE) {
994
0
              smart_str_appends(&str, "true");
995
92
            } else if (Z_TYPE_P(zv) == IS_NULL) {
996
32
              smart_str_appends(&str, "null");
997
60
            } else if (Z_TYPE_P(zv) == IS_STRING) {
998
4
              smart_str_appendc(&str, '\'');
999
4
              smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
1000
4
              if (Z_STRLEN_P(zv) > 10) {
1001
2
                smart_str_appends(&str, "...");
1002
2
              }
1003
4
              smart_str_appendc(&str, '\'');
1004
56
            } else if (Z_TYPE_P(zv) == IS_ARRAY) {
1005
4
              if (zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0) {
1006
2
                smart_str_appends(&str, "[]");
1007
2
              } else {
1008
2
                smart_str_appends(&str, "[...]");
1009
2
              }
1010
52
            } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
1011
38
              zend_ast *ast = Z_ASTVAL_P(zv);
1012
38
              if (ast->kind == ZEND_AST_CONSTANT) {
1013
10
                smart_str_append(&str, zend_ast_get_constant_name(ast));
1014
28
              } else if (ast->kind == ZEND_AST_CLASS_CONST
1015
28
               && ast->child[1]->kind == ZEND_AST_ZVAL
1016
26
               && Z_TYPE_P(zend_ast_get_zval(ast->child[1])) == IS_STRING) {
1017
26
                smart_str_append(&str, zend_ast_get_str(ast->child[0]));
1018
26
                smart_str_appends(&str, "::");
1019
26
                smart_str_append(&str, zend_ast_get_str(ast->child[1]));
1020
26
              } else {
1021
2
                smart_str_appends(&str, "<expression>");
1022
2
              }
1023
38
            } else {
1024
14
              zend_string *tmp_zv_str;
1025
14
              zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str);
1026
14
              smart_str_append(&str, zv_str);
1027
14
              zend_tmp_string_release(tmp_zv_str);
1028
14
            }
1029
94
          }
1030
94
        }
1031
122
      }
1032
1033
390
      if (++i < num_args) {
1034
154
        smart_str_appends(&str, ", ");
1035
154
      }
1036
390
      arg_info++;
1037
390
    }
1038
428
  }
1039
1040
476
  smart_str_appendc(&str, ')');
1041
1042
476
  if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1043
284
    smart_str_appends(&str, ": ");
1044
284
    zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, true);
1045
284
  }
1046
476
  smart_str_0(&str);
1047
1048
476
  return str.s;
1049
476
}
1050
/* }}} */
1051
1052
244
static zend_always_inline zend_string *func_filename(const zend_function *fn) {
1053
244
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
1054
244
}
1055
1056
244
static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
1057
244
  return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
1058
244
}
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
238
    inheritance_status status) {
1064
238
  zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
1065
238
  zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
1066
238
  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
42
    const zend_string *unresolved_class = NULL;
1070
42
    ZEND_HASH_MAP_FOREACH_STR_KEY(CG(delayed_autoloads), unresolved_class) {
1071
42
      break;
1072
126
    } ZEND_HASH_FOREACH_END();
1073
42
    ZEND_ASSERT(unresolved_class);
1074
1075
42
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1076
42
      "Could not check compatibility between %s and %s, because class %s is not available",
1077
42
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
1078
196
  } else if (status == INHERITANCE_WARNING) {
1079
28
    const zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
1080
28
      child->common.attributes,
1081
28
      "returntypewillchange",
1082
28
      sizeof("returntypewillchange")-1
1083
28
    );
1084
1085
28
    if (!return_type_will_change_attribute) {
1086
20
      zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1087
20
        "Return type of %s should either be compatible with %s, "
1088
20
        "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1089
20
        ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1090
20
      ZEND_ASSERT(!EG(exception));
1091
20
    }
1092
168
  } else {
1093
168
    zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1094
168
      "Declaration of %s must be compatible with %s",
1095
168
      ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1096
168
  }
1097
238
  zend_string_efree(child_prototype);
1098
238
  zend_string_efree(parent_prototype);
1099
238
}
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
3.74k
{
1106
3.74k
  inheritance_status status =
1107
3.74k
    zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1108
3.74k
  if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
1109
272
    if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
1110
82
      add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1111
190
    } else {
1112
190
      ZEND_ASSERT(status == INHERITANCE_ERROR || status == INHERITANCE_WARNING);
1113
190
      emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1114
190
    }
1115
272
  }
1116
3.74k
}
1117
1118
7.68k
#define ZEND_INHERITANCE_LAZY_CHILD_CLONE     (1<<0)
1119
5.21k
#define ZEND_INHERITANCE_CHECK_SILENT         (1<<1) /* don't throw errors */
1120
23.6k
#define ZEND_INHERITANCE_CHECK_PROTO          (1<<2) /* check method prototype (it might be already checked before) */
1121
8.47k
#define ZEND_INHERITANCE_CHECK_VISIBILITY     (1<<3)
1122
6.81k
#define ZEND_INHERITANCE_SET_CHILD_CHANGED    (1<<4)
1123
8.51k
#define ZEND_INHERITANCE_SET_CHILD_PROTO      (1<<5)
1124
8.10k
#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
5.15k
{
1131
5.15k
  uint32_t child_flags;
1132
5.15k
  uint32_t parent_flags = parent->common.fn_flags;
1133
5.15k
  zend_function *proto;
1134
1135
5.15k
#define SEPARATE_METHOD() do { \
1136
3.93k
      if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1137
3.93k
       && 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
3.93k
       && !(child_scope->ce_flags & ZEND_ACC_TRAIT) \
1142
3.93k
       && child->type == ZEND_USER_FUNCTION) { \
1143
        /* op_array wasn't duplicated yet */ \
1144
4
        zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); \
1145
4
        memcpy(new_function, child, sizeof(zend_op_array)); \
1146
4
        Z_PTR_P(child_zv) = child = new_function; \
1147
4
        flags &= ~ZEND_INHERITANCE_LAZY_CHILD_CLONE; \
1148
4
      } \
1149
3.93k
    } while(0)
1150
1151
5.15k
  if (UNEXPECTED((parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_ABSTRACT|ZEND_ACC_CTOR)) == ZEND_ACC_PRIVATE)) {
1152
112
    if (flags & ZEND_INHERITANCE_SET_CHILD_CHANGED) {
1153
62
      SEPARATE_METHOD();
1154
62
      child->common.fn_flags |= ZEND_ACC_CHANGED;
1155
62
    }
1156
    /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
1157
112
    return INHERITANCE_SUCCESS;
1158
112
  }
1159
1160
5.04k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO) && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
1161
4
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1162
0
      return INHERITANCE_ERROR;
1163
0
    }
1164
4
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1165
4
      "Cannot override final method %s::%s()",
1166
4
      ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
1167
4
  }
1168
1169
5.04k
  child_flags = child->common.fn_flags;
1170
  /* You cannot change from static to non static and vice versa.
1171
   */
1172
5.04k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1173
4.56k
   && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
1174
4
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1175
0
      return INHERITANCE_ERROR;
1176
0
    }
1177
4
    if (child_flags & ZEND_ACC_STATIC) {
1178
2
      zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1179
2
        "Cannot make non static method %s::%s() static in class %s",
1180
2
        ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1181
2
    } else {
1182
2
      zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1183
2
        "Cannot make static method %s::%s() non static in class %s",
1184
2
        ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1185
2
    }
1186
4
  }
1187
1188
  /* Disallow making an inherited method abstract. */
1189
5.03k
  if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1190
4.56k
   && 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
5.03k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_CHANGED)
1200
1.11k
   && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
1201
2
    SEPARATE_METHOD();
1202
2
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1203
2
  }
1204
1205
5.03k
  proto = parent->common.prototype ?
1206
4.86k
    parent->common.prototype : parent;
1207
1208
5.03k
  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
286
    if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1212
236
      return INHERITANCE_SUCCESS;
1213
236
    }
1214
50
    parent = proto;
1215
50
  }
1216
1217
4.80k
  if ((flags & ZEND_INHERITANCE_SET_CHILD_PROTO)
1218
3.95k
   && child->common.prototype != proto) {
1219
3.84k
    SEPARATE_METHOD();
1220
3.84k
    child->common.prototype = proto;
1221
3.84k
  }
1222
1223
  /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1224
4.80k
  if ((flags & ZEND_INHERITANCE_CHECK_VISIBILITY)
1225
4.29k
      && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1226
12
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1227
6
      return INHERITANCE_ERROR;
1228
6
    }
1229
6
    zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1230
6
      "Access level to %s::%s() must be %s (as in class %s)%s",
1231
6
      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
12
  }
1233
1234
4.78k
  if (flags & ZEND_INHERITANCE_CHECK_PROTO) {
1235
4.39k
    if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1236
655
      return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1237
655
    }
1238
3.74k
    perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1239
3.74k
  }
1240
1241
4.13k
  if ((flags & ZEND_INHERITANCE_RESET_CHILD_OVERRIDE)
1242
3.97k
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1243
30
    SEPARATE_METHOD();
1244
30
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1245
30
  }
1246
1247
4.13k
#undef SEPARATE_METHOD
1248
1249
4.13k
  return INHERITANCE_SUCCESS;
1250
4.78k
}
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
9.93k
{
1255
9.93k
  zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1256
1257
9.93k
  if (child) {
1258
4.13k
    zend_function *func = (zend_function*)Z_PTR_P(child);
1259
1260
4.13k
    if (is_interface && UNEXPECTED(func == parent)) {
1261
      /* The same method in interface may be inherited few times */
1262
0
      return;
1263
0
    }
1264
1265
4.13k
    do_inheritance_check_on_method(
1266
4.13k
      func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1267
5.80k
  } else {
1268
1269
5.80k
    if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1270
162
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1271
162
    }
1272
1273
5.80k
    parent = zend_duplicate_function(parent, ce);
1274
1275
5.80k
    if (!is_interface) {
1276
5.64k
      _zend_hash_append_ptr(&ce->function_table, key, parent);
1277
5.64k
    } else {
1278
154
      zend_hash_add_new_ptr(&ce->function_table, key, parent);
1279
154
    }
1280
5.80k
  }
1281
9.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
484
    prop_variance variance) {
1287
484
  if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
1288
418
      && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1289
252
    return INHERITANCE_SUCCESS;
1290
252
  }
1291
1292
232
  if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1293
6
    return INHERITANCE_ERROR;
1294
6
  }
1295
1296
  /* Perform a covariant type check in both directions to determined invariance. */
1297
226
  inheritance_status status1 = variance == PROP_CONTRAVARIANT ? INHERITANCE_SUCCESS :
1298
226
    zend_perform_covariant_type_check(
1299
214
      child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1300
226
  inheritance_status status2 = variance == PROP_COVARIANT ? INHERITANCE_SUCCESS :
1301
226
    zend_perform_covariant_type_check(
1302
216
      parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1303
226
  if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1304
60
    return INHERITANCE_SUCCESS;
1305
60
  }
1306
166
  if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1307
54
    return INHERITANCE_ERROR;
1308
54
  }
1309
112
  ZEND_ASSERT(status1 == INHERITANCE_UNRESOLVED || status2 == INHERITANCE_UNRESOLVED);
1310
112
  return INHERITANCE_UNRESOLVED;
1311
112
}
1312
1313
static ZEND_COLD void emit_incompatible_property_error(
1314
52
    const zend_property_info *child, const zend_property_info *parent, prop_variance variance) {
1315
52
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1316
52
  zend_error_noreturn(E_COMPILE_ERROR,
1317
52
    "Type of %s::$%s must be %s%s (as in class %s)",
1318
52
    ZSTR_VAL(child->ce->name),
1319
52
    zend_get_unmangled_property_name(child->name),
1320
52
    variance == PROP_INVARIANT ? "" :
1321
52
    variance == PROP_COVARIANT ? "subtype of " : "supertype of ",
1322
52
    ZSTR_VAL(type_str),
1323
52
    ZSTR_VAL(parent->ce->name));
1324
52
}
1325
1326
static ZEND_COLD void emit_set_hook_type_error(const zend_property_info *child, const zend_property_info *parent)
1327
2
{
1328
2
  zend_type set_type = parent->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1329
2
  zend_string *type_str = zend_type_to_string_resolved(set_type, parent->ce);
1330
2
  zend_error_noreturn(E_COMPILE_ERROR,
1331
2
    "Set type of %s::$%s must be supertype of %s (as in %s %s)",
1332
2
    ZSTR_VAL(child->ce->name),
1333
2
    zend_get_unmangled_property_name(child->name),
1334
2
    ZSTR_VAL(type_str),
1335
2
    zend_get_object_type_case(parent->ce, false),
1336
2
    ZSTR_VAL(parent->ce->name));
1337
2
}
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
484
) {
1346
484
  inheritance_status result = full_property_types_compatible(parent_info, child_info, variance);
1347
484
  if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1348
52
    emit_incompatible_property_error(child_info, parent_info, variance);
1349
52
  }
1350
484
  if (result != INHERITANCE_SUCCESS) {
1351
120
    return result;
1352
120
  }
1353
364
  if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1354
74
    ZEND_ASSERT(parent_info->hooks);
1355
74
    if (parent_info->hooks[ZEND_PROPERTY_HOOK_SET]
1356
30
     && (!child_info->hooks || !child_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1357
14
      zend_type set_type = parent_info->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1358
14
      inheritance_status result = zend_perform_covariant_type_check(
1359
14
        parent_info->ce, set_type, child_info->ce, child_info->type);
1360
14
      if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1361
2
        emit_set_hook_type_error(child_info, parent_info);
1362
2
      }
1363
14
    }
1364
74
  }
1365
364
  return INHERITANCE_SUCCESS;
1366
364
}
1367
1368
static bool property_has_operation(const zend_property_info *prop_info, zend_property_hook_kind kind)
1369
64
{
1370
64
  return (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1371
58
      && (kind == ZEND_PROPERTY_HOOK_GET || !(prop_info->flags & ZEND_ACC_READONLY)))
1372
8
    || (prop_info->hooks && prop_info->hooks[kind]);
1373
64
}
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
442
) {
1381
442
  zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
1382
442
  zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;
1383
1384
442
  if (child
1385
210
   && (child->common.fn_flags & ZEND_ACC_OVERRIDE)
1386
12
   && property_has_operation(parent_info, kind)) {
1387
10
    child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1388
10
  }
1389
1390
442
  if (!parent) {
1391
254
    return;
1392
254
  }
1393
1394
188
  if (!child) {
1395
80
    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
52
      if (property_has_operation(child_info, kind)) {
1398
48
        return;
1399
48
      }
1400
4
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1401
4
    }
1402
32
    if (!child_info->hooks) {
1403
16
      ce->num_hooked_props++;
1404
16
      child_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1405
16
      memset(child_info->hooks, 0, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1406
16
    }
1407
32
    child_info->hooks[kind] = zend_duplicate_function(parent, ce);
1408
32
    return;
1409
80
  }
1410
1411
108
  child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1412
1413
108
  uint32_t parent_flags = parent->common.fn_flags;
1414
108
  if (parent_flags & ZEND_ACC_PRIVATE) {
1415
0
    child->common.fn_flags |= ZEND_ACC_CHANGED;
1416
0
    return;
1417
0
  }
1418
1419
108
  if (parent_flags & ZEND_ACC_FINAL) {
1420
2
    zend_error_noreturn(E_COMPILE_ERROR,
1421
2
      "Cannot override final property hook %s::%s()",
1422
2
      ZSTR_VAL(parent->common.scope->name),
1423
2
      ZSTR_VAL(parent->common.function_name));
1424
2
  }
1425
1426
106
  do_inheritance_check_on_method(
1427
106
    child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
1428
106
    ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY
1429
106
      | ZEND_INHERITANCE_SET_CHILD_CHANGED | ZEND_INHERITANCE_SET_CHILD_PROTO
1430
106
      | 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
106
}
1436
1437
597
static prop_variance prop_get_variance(const zend_property_info *prop_info) {
1438
597
  bool unbacked = prop_info->flags & ZEND_ACC_VIRTUAL;
1439
597
  if (unbacked && prop_info->hooks) {
1440
166
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1441
94
      return PROP_COVARIANT;
1442
94
    }
1443
72
    if (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
1444
26
      return PROP_CONTRAVARIANT;
1445
26
    }
1446
72
  }
1447
477
  return PROP_INVARIANT;
1448
597
}
1449
1450
static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1451
2.51k
{
1452
2.51k
  zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1453
1454
2.51k
  if (UNEXPECTED(child)) {
1455
509
    zend_property_info *child_info = Z_PTR_P(child);
1456
509
    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1457
102
      child_info->flags |= ZEND_ACC_CHANGED;
1458
102
    }
1459
509
    if (parent_info->flags & ZEND_ACC_FINAL) {
1460
8
      zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final property %s::$%s",
1461
8
        ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key));
1462
8
    }
1463
501
    if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1464
401
      if (!(parent_info->ce->ce_flags & ZEND_ACC_INTERFACE)) {
1465
373
        child_info->prototype = parent_info->prototype;
1466
373
      }
1467
1468
401
      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
401
      if (UNEXPECTED((child_info->flags & ZEND_ACC_READONLY) != (parent_info->flags & ZEND_ACC_READONLY))) {
1474
10
        if (!(parent_info->flags & ZEND_ACC_ABSTRACT)) {
1475
4
          zend_error_noreturn(E_COMPILE_ERROR,
1476
4
            "Cannot redeclare %s property %s::$%s as %s %s::$%s",
1477
4
            parent_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1478
4
            ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1479
4
            child_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1480
4
            ZSTR_VAL(ce->name), ZSTR_VAL(key));
1481
4
        }
1482
10
      }
1483
397
      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
44
       && !(parent_info->hooks && (parent_info->flags & ZEND_ACC_VIRTUAL) && !parent_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1486
28
        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
28
        if (!parent_set_visibility) {
1490
8
          parent_set_visibility = zend_visibility_to_set_visibility(parent_info->flags & ZEND_ACC_PPP_MASK);
1491
8
        }
1492
28
        uint32_t child_set_visibility = child_info->flags & ZEND_ACC_PPP_SET_MASK;
1493
28
        if (child_set_visibility > parent_set_visibility) {
1494
8
          zend_error_noreturn(
1495
8
            E_COMPILE_ERROR,
1496
8
            "Set access level of %s::$%s must be %s (as in class %s)%s",
1497
8
            ZSTR_VAL(ce->name), ZSTR_VAL(key),
1498
8
            zend_asymmetric_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name),
1499
8
            !(parent_info->flags & ZEND_ACC_PPP_SET_MASK) ? "" : " or weaker");
1500
8
        }
1501
28
      }
1502
1503
389
      if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1504
2
        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
2
      }
1506
387
      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
231
        bool use_child_prop = !parent_info->hooks && child_info->hooks;
1511
1512
231
        if (use_child_prop && child_info->offset == ZEND_VIRTUAL_PROPERTY_OFFSET) {
1513
38
          child_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
1514
38
          ce->default_properties_count++;
1515
38
          ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1516
38
          zval *property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(child_info->offset)];
1517
38
          ZVAL_UNDEF(property_default_ptr);
1518
38
          Z_PROP_FLAG_P(property_default_ptr) = IS_PROP_UNINIT;
1519
38
        }
1520
1521
231
        int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
1522
231
        if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1523
          /* Don't keep default properties in GC (they may be freed by opcache) */
1524
215
          zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1525
1526
215
          if (use_child_prop) {
1527
74
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1528
141
          } else {
1529
141
            int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1530
141
            ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1531
141
            ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1532
141
          }
1533
215
        } else {
1534
          /* Default value was removed in child, remove it from parent too. */
1535
16
          if (ZEND_TYPE_IS_SET(child_info->type)) {
1536
10
            ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1537
10
          } else {
1538
6
            ZVAL_NULL(&ce->default_properties_table[parent_num]);
1539
6
          }
1540
16
        }
1541
1542
231
        if (!use_child_prop) {
1543
157
          child_info->offset = parent_info->offset;
1544
157
        }
1545
231
        child_info->flags &= ~ZEND_ACC_VIRTUAL;
1546
231
      }
1547
1548
387
      if (parent_info->hooks || child_info->hooks) {
1549
667
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1550
442
          inherit_property_hook(ce, parent_info, child_info, i);
1551
442
        }
1552
225
      }
1553
1554
387
      prop_variance variance = prop_get_variance(parent_info);
1555
387
      if (ZEND_TYPE_IS_SET(parent_info->type)) {
1556
204
        inheritance_status status = verify_property_type_compatibility(
1557
204
          parent_info, child_info, variance, true, false);
1558
204
        if (status == INHERITANCE_UNRESOLVED) {
1559
22
          add_property_compatibility_obligation(ce, child_info, parent_info, variance);
1560
22
        }
1561
204
      } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1562
4
        zend_error_noreturn(E_COMPILE_ERROR,
1563
4
            "Type of %s::$%s must be omitted to match the parent definition in class %s",
1564
4
            ZSTR_VAL(ce->name),
1565
4
            ZSTR_VAL(key),
1566
4
            ZSTR_VAL(parent_info->ce->name));
1567
4
      }
1568
1569
383
      if (child_info->ce == ce) {
1570
329
        child_info->flags &= ~ZEND_ACC_OVERRIDE;
1571
329
      }
1572
383
    }
1573
2.01k
  } else {
1574
2.01k
    zend_function **hooks = parent_info->hooks;
1575
2.01k
    if (hooks) {
1576
75
      ce->num_hooked_props++;
1577
75
      if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1578
10
        ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1579
10
      }
1580
75
    }
1581
1582
2.01k
    _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1583
2.01k
  }
1584
2.51k
}
1585
/* }}} */
1586
1587
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1588
3.10k
{
1589
3.10k
  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
3.10k
  ZEND_ASSERT(ce != iface);
1594
3.10k
}
1595
/* }}} */
1596
1597
static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1598
766
{
1599
  /* expects interface to be contained in ce's interface list already */
1600
766
  uint32_t i, ce_num, if_num = iface->num_interfaces;
1601
1602
766
  ce_num = ce->num_interfaces;
1603
1604
766
  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
530
  } else {
1607
530
    ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1608
530
  }
1609
1610
  /* Inherit the interfaces, only if they're not already inherited by the class */
1611
1.98k
  while (if_num--) {
1612
1.21k
    zend_class_entry *entry = iface->interfaces[if_num];
1613
1.52k
    for (i = 0; i < ce_num; i++) {
1614
602
      if (ce->interfaces[i] == entry) {
1615
296
        break;
1616
296
      }
1617
602
    }
1618
1.21k
    if (i == ce_num) {
1619
922
      ce->interfaces[ce->num_interfaces++] = entry;
1620
922
    }
1621
1.21k
  }
1622
766
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1623
1624
  /* and now call the implementing handlers */
1625
1.68k
  while (ce_num < ce->num_interfaces) {
1626
922
    do_implement_interface(ce, ce->interfaces[ce_num++]);
1627
922
  }
1628
766
}
1629
/* }}} */
1630
1631
static void emit_incompatible_class_constant_error(
1632
8
    const zend_class_constant *child, const zend_class_constant *parent, const zend_string *const_name) {
1633
8
  zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1634
8
  zend_error_noreturn(E_COMPILE_ERROR,
1635
8
    "Type of %s::%s must be compatible with %s::%s of type %s",
1636
8
    ZSTR_VAL(child->ce->name),
1637
8
    ZSTR_VAL(const_name),
1638
8
    ZSTR_VAL(parent->ce->name),
1639
8
    ZSTR_VAL(const_name),
1640
8
    ZSTR_VAL(type_str));
1641
8
}
1642
1643
static inheritance_status class_constant_types_compatible(const zend_class_constant *parent, const zend_class_constant *child)
1644
56
{
1645
56
  ZEND_ASSERT(ZEND_TYPE_IS_SET(parent->type));
1646
1647
56
  if (!ZEND_TYPE_IS_SET(child->type)) {
1648
4
    return INHERITANCE_ERROR;
1649
4
  }
1650
1651
52
  return zend_perform_covariant_type_check(child->ce, child->type, parent->ce, parent->type);
1652
56
}
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
884
{
1659
884
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1660
884
  zend_class_constant *c;
1661
1662
884
  if (zv != NULL) {
1663
102
    c = (zend_class_constant*)Z_PTR_P(zv);
1664
102
    bool inherit = do_inherit_constant_check(ce, parent_const, name);
1665
102
    ZEND_ASSERT(!inherit);
1666
782
  } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1667
776
    if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1668
58
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1669
58
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1670
58
      if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
1671
14
        c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1672
14
        memcpy(c, parent_const, sizeof(zend_class_constant));
1673
14
        parent_const = c;
1674
14
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1675
14
      }
1676
58
    }
1677
776
    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
776
    _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1683
776
  }
1684
884
}
1685
/* }}} */
1686
1687
void zend_build_properties_info_table(zend_class_entry *ce)
1688
12.4k
{
1689
12.4k
  zend_property_info **table, *prop;
1690
12.4k
  size_t size;
1691
12.4k
  if (ce->default_properties_count == 0) {
1692
7.88k
    return;
1693
7.88k
  }
1694
1695
4.52k
  ZEND_ASSERT(ce->properties_info_table == NULL);
1696
4.52k
  size = sizeof(zend_property_info *) * ce->default_properties_count;
1697
4.52k
  if (ce->type == ZEND_USER_CLASS) {
1698
4.42k
    ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1699
4.42k
  } 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
4.52k
  memset(table, 0, size);
1705
1706
4.52k
  if (ce->parent && ce->parent->default_properties_count != 0) {
1707
738
    zend_property_info **parent_table = ce->parent->properties_info_table;
1708
738
    memcpy(
1709
738
      table, parent_table,
1710
738
      sizeof(zend_property_info *) * ce->parent->default_properties_count
1711
738
    );
1712
1713
    /* Child did not add any new properties, we are done */
1714
738
    if (ce->default_properties_count == ce->parent->default_properties_count) {
1715
461
      return;
1716
461
    }
1717
738
  }
1718
1719
21.1k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, prop) {
1720
21.1k
    if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0
1721
6.01k
     && !(prop->flags & ZEND_ACC_VIRTUAL)) {
1722
5.88k
      const zend_property_info *root_prop = prop->prototype;
1723
5.88k
      if (UNEXPECTED(root_prop->flags & ZEND_ACC_VIRTUAL)) {
1724
        /* Prototype is virtual, we need to manually hunt down the first backed property. */
1725
32
        root_prop = prop;
1726
32
        zend_class_entry *parent_ce;
1727
38
        while ((parent_ce = root_prop->ce->parent)) {
1728
38
          zend_property_info *parent_prop = zend_hash_find_ptr(&parent_ce->properties_info, key);
1729
38
          if (!parent_prop
1730
38
           || parent_prop->prototype != prop->prototype
1731
38
           || (parent_prop->flags & ZEND_ACC_VIRTUAL)) {
1732
32
            break;
1733
32
          }
1734
6
          root_prop = parent_prop;
1735
6
        }
1736
32
      }
1737
5.88k
      uint32_t prop_table_offset = OBJ_PROP_TO_NUM(root_prop->offset);
1738
5.88k
      table[prop_table_offset] = prop;
1739
5.88k
    }
1740
21.1k
  } ZEND_HASH_FOREACH_END();
1741
4.06k
}
1742
1743
ZEND_API void zend_verify_hooked_property(const zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name)
1744
738
{
1745
738
  if (!prop_info->hooks) {
1746
0
    return;
1747
0
  }
1748
738
  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
738
  if ((prop_info->flags & ZEND_ACC_VIRTUAL) && prop_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1752
6
    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
6
    } else {
1755
6
      zend_error_noreturn(E_COMPILE_ERROR,
1756
6
        "Cannot specify default value for virtual hooked property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1757
6
    }
1758
6
  }
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
732
  if (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1762
311
   && !ZEND_TYPE_IS_SET(prop_info->type)
1763
203
   && Z_TYPE(ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]) == IS_UNDEF) {
1764
86
    ZVAL_NULL(&ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]);
1765
86
  }
1766
2.19k
  for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1767
1.46k
    const zend_function *func = prop_info->hooks[i];
1768
1.46k
    if (func) {
1769
969
      if ((zend_property_hook_kind)i == ZEND_PROPERTY_HOOK_GET
1770
593
       && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1771
46
       && !(prop_info->flags & ZEND_ACC_VIRTUAL)
1772
8
       && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1773
2
        zend_error_noreturn(E_COMPILE_ERROR, "Get hook of backed property %s::%s with set hook may not return by reference",
1774
2
          ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1775
2
      }
1776
967
      if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
1777
122
        abstract_error = false;
1778
122
      }
1779
967
    }
1780
1.46k
  }
1781
730
  if (abstract_error) {
1782
2
    zend_error_noreturn(E_COMPILE_ERROR,
1783
2
      "Abstract property %s::$%s must specify at least one abstract hook", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1784
2
  }
1785
728
  if ((prop_info->flags & ZEND_ACC_VIRTUAL)
1786
419
   && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)
1787
22
   && (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET] || !prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1788
4
    const char *prefix = !prop_info->hooks[ZEND_PROPERTY_HOOK_GET]
1789
4
      ? "set-only" : "get-only";
1790
4
    zend_error_noreturn(E_COMPILE_ERROR,
1791
4
      "%s virtual property %s::$%s must not specify asymmetric visibility",
1792
4
      prefix, ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1793
4
  }
1794
728
}
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
6
{
1798
6
  zend_error_noreturn(E_COMPILE_ERROR, "Type of parameter $%s of hook %s::$%s::set must be compatible with property type",
1799
6
    ZSTR_VAL(value_param_name), ZSTR_VAL(class_name), zend_get_unmangled_property_name(prop_name));
1800
6
}
1801
1802
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info)
1803
4
{
1804
4
  zend_string *value_param_name = prop_info->hooks[ZEND_PROPERTY_HOOK_SET]->op_array.arg_info[0].name;
1805
4
  zend_hooked_property_variance_error_ex(value_param_name, prop_info->ce->name, prop_info->name);
1806
4
}
1807
1808
ZEND_API inheritance_status zend_verify_property_hook_variance(const zend_property_info *prop_info, const zend_function *func)
1809
394
{
1810
394
  ZEND_ASSERT(prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET] == func);
1811
1812
394
  zend_arg_info *value_arg_info = &func->op_array.arg_info[0];
1813
394
  if (!ZEND_TYPE_IS_SET(value_arg_info->type)) {
1814
238
    return INHERITANCE_SUCCESS;
1815
238
  }
1816
1817
156
  if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1818
0
    return INHERITANCE_ERROR;
1819
0
  }
1820
1821
156
  zend_class_entry *ce = prop_info->ce;
1822
156
  return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type);
1823
156
}
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
2.30k
{
1848
2.30k
  zend_property_info *property_info;
1849
2.30k
  zend_string *key;
1850
1851
2.30k
  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
2.30k
  } 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
12
    if (parent_ce->ce_flags & ZEND_ACC_ENUM) {
1860
4
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend enum %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1861
4
    }
1862
    /* Class must not extend a final class */
1863
8
    if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1864
6
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1865
6
    }
1866
1867
    /* Class declaration must not extend traits or interfaces */
1868
2
    if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1869
2
      zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1870
2
        ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1871
2
      );
1872
2
    }
1873
2
  }
1874
1875
2.29k
  if (UNEXPECTED((ce->ce_flags & ZEND_ACC_READONLY_CLASS) != (parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS))) {
1876
2
    zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1877
2
      ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1878
2
      parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1879
2
    );
1880
2
  }
1881
1882
2.28k
  if (ce->parent_name) {
1883
2.13k
    zend_string_release_ex(ce->parent_name, 0);
1884
2.13k
  }
1885
2.28k
  ce->parent = parent_ce;
1886
2.28k
  ce->default_object_handlers = parent_ce->default_object_handlers;
1887
2.28k
  ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1888
1889
  /* Inherit properties */
1890
2.28k
  if (parent_ce->default_properties_count) {
1891
788
    zval *src, *dst, *end;
1892
1893
788
    if (ce->default_properties_count) {
1894
295
      zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1895
295
      src = ce->default_properties_table + ce->default_properties_count;
1896
295
      end = table + parent_ce->default_properties_count;
1897
295
      dst = end + ce->default_properties_count;
1898
295
      ce->default_properties_table = table;
1899
375
      do {
1900
375
        dst--;
1901
375
        src--;
1902
375
        ZVAL_COPY_VALUE_PROP(dst, src);
1903
375
      } while (dst != end);
1904
295
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1905
295
      end = ce->default_properties_table;
1906
493
    } else {
1907
493
      end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1908
493
      dst = end + parent_ce->default_properties_count;
1909
493
      ce->default_properties_table = end;
1910
493
    }
1911
788
    src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1912
788
    if (UNEXPECTED(parent_ce->type != ce->type)) {
1913
      /* User class extends internal */
1914
680
      do {
1915
680
        dst--;
1916
680
        src--;
1917
        /* We don't have to account for refcounting because
1918
         * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1919
680
        ZEND_ASSERT(!Z_REFCOUNTED_P(src));
1920
680
        ZVAL_COPY_VALUE_PROP(dst, src);
1921
680
        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
680
        continue;
1926
680
      } while (dst != end);
1927
670
    } else {
1928
1.45k
      do {
1929
1.45k
        dst--;
1930
1.45k
        src--;
1931
1.45k
        ZVAL_COPY_PROP(dst, src);
1932
1.45k
        if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1933
14
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1934
14
          ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1935
14
        }
1936
1.45k
        continue;
1937
1.45k
      } while (dst != end);
1938
670
    }
1939
788
    ce->default_properties_count += parent_ce->default_properties_count;
1940
788
  }
1941
1942
2.28k
  if (parent_ce->default_static_members_count) {
1943
116
    zval *src, *dst, *end;
1944
1945
116
    if (ce->default_static_members_count) {
1946
42
      zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1947
42
      src = ce->default_static_members_table + ce->default_static_members_count;
1948
42
      end = table + parent_ce->default_static_members_count;
1949
42
      dst = end + ce->default_static_members_count;
1950
42
      ce->default_static_members_table = table;
1951
56
      do {
1952
56
        dst--;
1953
56
        src--;
1954
56
        ZVAL_COPY_VALUE(dst, src);
1955
56
      } while (dst != end);
1956
42
      pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1957
42
      end = ce->default_static_members_table;
1958
74
    } else {
1959
74
      end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1960
74
      dst = end + parent_ce->default_static_members_count;
1961
74
      ce->default_static_members_table = end;
1962
74
    }
1963
116
    src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1964
174
    do {
1965
174
      dst--;
1966
174
      src--;
1967
174
      if (Z_TYPE_P(src) == IS_INDIRECT) {
1968
10
        ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1969
164
      } else {
1970
164
        ZVAL_INDIRECT(dst, src);
1971
164
      }
1972
174
      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
174
    } while (dst != end);
1977
116
    ce->default_static_members_count += parent_ce->default_static_members_count;
1978
116
    if (!ZEND_MAP_PTR(ce->static_members_table)) {
1979
116
      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
116
    }
1984
116
  }
1985
1986
6.12k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1987
6.12k
    if (property_info->ce == ce) {
1988
773
      if (property_info->flags & ZEND_ACC_STATIC) {
1989
114
        property_info->offset += parent_ce->default_static_members_count;
1990
659
      } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1991
509
        property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1992
509
      }
1993
773
    }
1994
6.12k
  } ZEND_HASH_FOREACH_END();
1995
1996
2.28k
  if (zend_hash_num_elements(&parent_ce->properties_info)) {
1997
992
    zend_hash_extend(&ce->properties_info,
1998
992
      zend_hash_num_elements(&ce->properties_info) +
1999
992
      zend_hash_num_elements(&parent_ce->properties_info), 0);
2000
2001
6.95k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
2002
6.95k
      do_inherit_property(property_info, key, ce);
2003
6.95k
    } ZEND_HASH_FOREACH_END();
2004
992
  }
2005
2006
2.28k
  if (ce->num_hooked_props) {
2007
1.11k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
2008
1.11k
      if (property_info->ce == ce && property_info->hooks) {
2009
205
        zend_verify_hooked_property(ce, property_info, key);
2010
205
      }
2011
1.11k
    } ZEND_HASH_FOREACH_END();
2012
179
  }
2013
2014
2.28k
  if (zend_hash_num_elements(&parent_ce->constants_table)) {
2015
233
    zend_class_constant *c;
2016
2017
233
    zend_hash_extend(&ce->constants_table,
2018
233
      zend_hash_num_elements(&ce->constants_table) +
2019
233
      zend_hash_num_elements(&parent_ce->constants_table), 0);
2020
2021
2.23k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
2022
2.23k
      do_inherit_class_constant(key, c, ce);
2023
2.23k
    } ZEND_HASH_FOREACH_END();
2024
233
  }
2025
2026
2.28k
  if (zend_hash_num_elements(&parent_ce->function_table)) {
2027
1.56k
    zend_hash_extend(&ce->function_table,
2028
1.56k
      zend_hash_num_elements(&ce->function_table) +
2029
1.56k
      zend_hash_num_elements(&parent_ce->function_table), 0);
2030
1.56k
    uint32_t flags =
2031
1.56k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2032
1.56k
      ZEND_INHERITANCE_SET_CHILD_CHANGED |
2033
1.56k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2034
1.56k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2035
2036
1.56k
    if (!checked) {
2037
580
      flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2038
580
    }
2039
1.56k
    zend_function *func;
2040
16.5k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
2041
16.5k
      do_inherit_method(key, func, ce, false, flags);
2042
16.5k
    } ZEND_HASH_FOREACH_END();
2043
1.56k
  }
2044
2045
2.28k
  do_inherit_parent_constructor(ce);
2046
2047
2.28k
  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
2.28k
  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
2.28k
}
2058
/* }}} */
2059
2060
static zend_always_inline bool check_trait_property_or_constant_value_compatibility(zend_class_entry *ce, zval *op1, zval *op2) /* {{{ */
2061
62
{
2062
62
  bool is_compatible;
2063
62
  zval op1_tmp, op2_tmp;
2064
2065
  /* if any of the values is a constant, we try to resolve it */
2066
62
  if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
2067
18
    ZVAL_COPY_OR_DUP(&op1_tmp, op1);
2068
18
    if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
2069
2
      zval_ptr_dtor(&op1_tmp);
2070
2
      return false;
2071
2
    }
2072
16
    op1 = &op1_tmp;
2073
16
  }
2074
60
  if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
2075
14
    ZVAL_COPY_OR_DUP(&op2_tmp, op2);
2076
14
    if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
2077
2
      zval_ptr_dtor(&op2_tmp);
2078
2
      return false;
2079
2
    }
2080
12
    op2 = &op2_tmp;
2081
12
  }
2082
2083
58
  is_compatible = fast_is_identical_function(op1, op2);
2084
2085
58
  if (op1 == &op1_tmp) {
2086
14
    zval_ptr_dtor_nogc(&op1_tmp);
2087
14
  }
2088
58
  if (op2 == &op2_tmp) {
2089
12
    zval_ptr_dtor_nogc(&op2_tmp);
2090
12
  }
2091
2092
58
  return is_compatible;
2093
60
}
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
288
) {
2100
288
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2101
288
  if (zv == NULL) {
2102
150
    return true;
2103
150
  }
2104
2105
138
  zend_class_constant *child_constant = Z_PTR_P(zv);
2106
138
  if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
2107
2
    zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
2108
2
      ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2109
2
      ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
2110
2
    );
2111
2
  }
2112
2113
136
  if (child_constant->ce != parent_constant->ce && child_constant->ce != ce) {
2114
8
    zend_error_noreturn(E_COMPILE_ERROR,
2115
8
      "%s %s inherits both %s::%s and %s::%s, which is ambiguous",
2116
8
      zend_get_object_type_uc(ce),
2117
8
      ZSTR_VAL(ce->name),
2118
8
      ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2119
8
      ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
2120
8
  }
2121
2122
128
  if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(child_constant) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PPP_MASK))) {
2123
2
    zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in %s %s)%s",
2124
2
      ZSTR_VAL(ce->name), ZSTR_VAL(name),
2125
2
      zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_constant)),
2126
2
      zend_get_object_type(parent_constant->ce),
2127
2
      ZSTR_VAL(parent_constant->ce->name),
2128
2
      (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PUBLIC) ? "" : " or weaker"
2129
2
    );
2130
2
  }
2131
2132
126
  if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
2133
38
    inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
2134
38
    if (status == INHERITANCE_ERROR) {
2135
6
      emit_incompatible_class_constant_error(child_constant, parent_constant, name);
2136
32
    } else if (status == INHERITANCE_UNRESOLVED) {
2137
2
      add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
2138
2
    }
2139
38
  }
2140
2141
126
  return false;
2142
128
}
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
178
{
2147
178
  if (do_inherit_constant_check(ce, c, name)) {
2148
150
    zend_class_constant *ct;
2149
150
    if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2150
4
      ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2151
4
      ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2152
4
      if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
2153
4
        ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2154
4
        memcpy(ct, c, sizeof(zend_class_constant));
2155
4
        c = ct;
2156
4
        Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2157
4
      }
2158
4
    }
2159
150
    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
150
    zend_hash_update_ptr(&ce->constants_table, name, c);
2165
150
  }
2166
178
}
2167
/* }}} */
2168
2169
static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2170
2.18k
{
2171
2.18k
  zend_function *func;
2172
2.18k
  zend_string *key;
2173
2.18k
  zend_class_constant *c;
2174
2.18k
  uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2175
2176
2.18k
  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
2.05k
    flags |=
2180
2.05k
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2181
2.05k
      ZEND_INHERITANCE_SET_CHILD_PROTO |
2182
2.05k
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2183
2.05k
  } else {
2184
134
    flags |=
2185
134
      ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2186
134
      ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2187
134
  }
2188
2189
4.72k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2190
4.72k
    do_inherit_iface_constant(key, c, ce, iface);
2191
4.72k
  } ZEND_HASH_FOREACH_END();
2192
2193
10.7k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2194
10.7k
    do_inherit_method(key, func, ce, true, flags);
2195
10.7k
  } ZEND_HASH_FOREACH_END();
2196
2197
2.18k
  zend_hash_extend(&ce->properties_info,
2198
2.17k
    zend_hash_num_elements(&ce->properties_info) +
2199
2.17k
    zend_hash_num_elements(&iface->properties_info), 0);
2200
2201
2.17k
  zend_property_info *prop;
2202
2.23k
  ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2203
2.23k
    do_inherit_property(prop, key, ce);
2204
2.23k
  } ZEND_HASH_FOREACH_END();
2205
2206
2.17k
  do_implement_interface(ce, iface);
2207
2.17k
  if (iface->num_interfaces) {
2208
440
    zend_do_inherit_interfaces(ce, iface);
2209
440
  }
2210
2.17k
}
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
1.60k
{
2257
1.60k
  uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2258
1.60k
  uint32_t num_interfaces = num_parent_interfaces;
2259
1.60k
  zend_string *key;
2260
1.60k
  zend_class_constant *c;
2261
1.60k
  uint32_t i;
2262
2263
3.63k
  for (i = 0; i < ce->num_interfaces; i++) {
2264
2.04k
    zend_class_entry *iface = interfaces[num_parent_interfaces + i];
2265
2.04k
    if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2266
0
      add_dependency_obligation(ce, iface);
2267
0
    }
2268
2.04k
    if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
2269
4
      efree(interfaces);
2270
4
      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
4
    }
2273
2.52k
    for (uint32_t j = 0; j < num_interfaces; j++) {
2274
507
      if (interfaces[j] == iface) {
2275
28
        if (j >= num_parent_interfaces) {
2276
8
          efree(interfaces);
2277
8
          zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
2278
8
            zend_get_object_type_uc(ce),
2279
8
            ZSTR_VAL(ce->name),
2280
8
            ZSTR_VAL(iface->name));
2281
0
          return;
2282
8
        }
2283
        /* skip duplications */
2284
56
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2285
56
          do_inherit_constant_check(ce, c, key);
2286
56
        } ZEND_HASH_FOREACH_END();
2287
2288
20
        iface = NULL;
2289
20
        break;
2290
20
      }
2291
507
    }
2292
2.03k
    if (iface) {
2293
2.01k
      interfaces[num_interfaces] = iface;
2294
2.01k
      num_interfaces++;
2295
2.01k
    }
2296
2.03k
  }
2297
2298
1.59k
  if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2299
24
    for (i = 0; i < ce->num_interfaces; i++) {
2300
12
      zend_string_release_ex(ce->interface_names[i].name, 0);
2301
12
      zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2302
12
    }
2303
12
    efree(ce->interface_names);
2304
12
  }
2305
2306
1.59k
  ce->num_interfaces = num_interfaces;
2307
1.59k
  ce->interfaces = interfaces;
2308
1.59k
  ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2309
2310
1.64k
  for (i = 0; i < num_parent_interfaces; i++) {
2311
58
    do_implement_interface(ce, ce->interfaces[i]);
2312
58
  }
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
3.58k
  for (; i < num_interfaces; i++) {
2316
1.99k
    do_interface_implementation(ce, ce->interfaces[i]);
2317
1.99k
  }
2318
1.59k
}
2319
/* }}} */
2320
2321
2322
void zend_inheritance_check_override(const zend_class_entry *ce)
2323
12.1k
{
2324
12.1k
  if (ce->ce_flags & ZEND_ACC_TRAIT) {
2325
776
    return;
2326
776
  }
2327
2328
51.1k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *f) {
2329
51.1k
    if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2330
10
      ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2331
2332
10
      zend_error_at_noreturn(
2333
10
        E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2334
10
        "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2335
10
        ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2336
10
    }
2337
51.1k
  } ZEND_HASH_FOREACH_END();
2338
2339
40.5k
  ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
2340
40.5k
    if (prop->flags & ZEND_ACC_OVERRIDE) {
2341
16
      zend_error_noreturn(
2342
16
        E_COMPILE_ERROR,
2343
16
        "%s::$%s has #[\\Override] attribute, but no matching parent property exists",
2344
16
        ZSTR_VAL(ce->name), zend_get_unmangled_property_name(prop->name));
2345
16
    }
2346
2347
8.91k
    if (prop->hooks) {
2348
2.28k
      for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2349
1.52k
        zend_function *f = prop->hooks[i];
2350
1.52k
        if (f && f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2351
4
          ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2352
2353
4
          zend_error_at_noreturn(
2354
4
            E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2355
4
            "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2356
4
            ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2357
4
        }
2358
1.52k
      }
2359
765
    }
2360
8.91k
  } ZEND_HASH_FOREACH_END();
2361
11.3k
}
2362
2363
2364
static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
2365
228
{
2366
  /* self in trait methods should be resolved to the using class, not the trait. */
2367
228
  return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
2368
228
}
2369
2370
static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
2371
898
{
2372
898
  zend_function *existing_fn = NULL;
2373
898
  zend_function *new_fn;
2374
2375
898
  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
158
    if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
2379
2
      (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
2380
2
      (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2381
2
      return;
2382
2
    }
2383
2384
    /* Abstract method signatures from the trait must be satisfied. */
2385
156
    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
114
      do_inheritance_check_on_method(
2392
114
        existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
2393
114
        ce, NULL, ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
2394
114
      return;
2395
114
    }
2396
2397
42
    if (existing_fn->common.scope == ce) {
2398
      /* members from the current class override trait methods */
2399
32
      return;
2400
32
    } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
2401
10
        && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
2402
      /* two traits can't define the same non-abstract method */
2403
10
      zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
2404
10
        ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
2405
10
        ZSTR_VAL(ce->name), ZSTR_VAL(name),
2406
10
        ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
2407
10
    }
2408
42
  }
2409
2410
740
  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
740
  } else {
2415
740
    new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2416
740
    memcpy(new_fn, fn, sizeof(zend_op_array));
2417
740
    new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2418
740
  }
2419
740
  new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2420
2421
  /* Reassign method name, in case it is an alias. */
2422
740
  new_fn->common.function_name = name;
2423
740
  function_add_ref(new_fn);
2424
740
  fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2425
740
  zend_add_magic_method(ce, fn, key);
2426
740
}
2427
/* }}} */
2428
2429
static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2430
1.04k
{
2431
1.04k
  if (fn->common.scope->ce_flags & ZEND_ACC_TRAIT) {
2432
2433
744
    fn->common.scope = ce;
2434
2435
744
    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2436
10
      ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2437
10
    }
2438
744
    if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2439
30
      ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2440
30
    }
2441
744
  }
2442
1.04k
}
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
898
{
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
898
  if (!(original_fn_flags & ZEND_ACC_FINAL)
2452
864
    && (fn_copy->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2453
6
    && !zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2454
6
    zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2455
6
  }
2456
898
}
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
820
{
2460
820
  zend_trait_alias  *alias, **alias_ptr;
2461
820
  zend_function      fn_copy;
2462
820
  int                i;
2463
2464
  /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2465
820
  if (ce->trait_aliases) {
2466
156
    alias_ptr = ce->trait_aliases;
2467
156
    alias = *alias_ptr;
2468
156
    i = 0;
2469
678
    while (alias) {
2470
      /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2471
522
      if (alias->alias != NULL
2472
268
        && fn->common.scope == aliases[i]
2473
144
        && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2474
522
      ) {
2475
98
        fn_copy = *fn;
2476
98
        if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2477
16
          fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2478
82
        } else {
2479
82
          fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2480
82
        }
2481
2482
98
        zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2483
2484
98
        zend_string *lcname = zend_string_tolower(alias->alias);
2485
98
        zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2486
98
        zend_string_release_ex(lcname, 0);
2487
98
      }
2488
522
      alias_ptr++;
2489
522
      alias = *alias_ptr;
2490
522
      i++;
2491
522
    }
2492
156
  }
2493
2494
820
  if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2495
    /* is not in hashtable, thus, function is not to be excluded */
2496
800
    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
800
    if (ce->trait_aliases) {
2500
148
      alias_ptr = ce->trait_aliases;
2501
148
      alias = *alias_ptr;
2502
148
      i = 0;
2503
648
      while (alias) {
2504
        /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2505
500
        if (alias->alias == NULL && alias->modifiers != 0
2506
250
          && fn->common.scope == aliases[i]
2507
232
          && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2508
500
        ) {
2509
56
          if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2510
30
            fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2511
30
          } else {
2512
26
            fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2513
26
          }
2514
56
        }
2515
500
        alias_ptr++;
2516
500
        alias = *alias_ptr;
2517
500
        i++;
2518
500
      }
2519
148
    }
2520
2521
800
    zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2522
2523
800
    zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2524
800
  }
2525
820
}
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
144
{
2530
144
  if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2531
4
    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
4
  }
2534
2535
204
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2536
198
    if (traits[i] == trait) {
2537
134
      return i;
2538
134
    }
2539
198
  }
2540
6
  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
140
}
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
648
{
2547
648
  size_t i, j = 0;
2548
648
  zend_trait_precedence *cur_precedence;
2549
648
  zend_trait_method_reference *cur_method_ref;
2550
648
  zend_string *lc_trait_name;
2551
648
  zend_string *lcname;
2552
648
  HashTable **exclude_tables = NULL;
2553
648
  zend_class_entry **aliases = NULL;
2554
648
  zend_class_entry *trait;
2555
2556
  /* resolve class references */
2557
648
  if (ce->trait_precedences) {
2558
32
    exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2559
32
    i = 0;
2560
32
    zend_trait_precedence **precedences = ce->trait_precedences;
2561
32
    ce->trait_precedences = NULL;
2562
62
    while ((cur_precedence = precedences[i])) {
2563
      /** Resolve classes for all precedence operations. */
2564
40
      cur_method_ref = &cur_precedence->trait_method;
2565
40
      lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2566
40
      trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2567
40
      zend_string_release_ex(lc_trait_name, 0);
2568
40
      if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2569
2
        zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2570
2
      }
2571
38
      zend_check_trait_usage(ce, trait, traits);
2572
2573
      /** Ensure that the preferred method is actually available. */
2574
38
      lcname = zend_string_tolower(cur_method_ref->method_name);
2575
38
      if (!zend_hash_exists(&trait->function_table, lcname)) {
2576
4
        zend_error_noreturn(E_COMPILE_ERROR,
2577
4
               "A precedence rule was defined for %s::%s but this method does not exist",
2578
4
               ZSTR_VAL(trait->name),
2579
4
               ZSTR_VAL(cur_method_ref->method_name));
2580
4
      }
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
62
      for (j = 0; j < cur_precedence->num_excludes; j++) {
2590
32
        zend_string* class_name = cur_precedence->exclude_class_names[j];
2591
32
        zend_class_entry *exclude_ce;
2592
32
        uint32_t trait_num;
2593
2594
32
        lc_trait_name = zend_string_tolower(class_name);
2595
32
        exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2596
32
        zend_string_release_ex(lc_trait_name, 0);
2597
32
        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
32
        trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2601
32
        if (!exclude_tables[trait_num]) {
2602
26
          ALLOC_HASHTABLE(exclude_tables[trait_num]);
2603
26
          zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2604
26
        }
2605
32
        if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2606
2
          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
2
        }
2608
2609
        /* make sure that the trait method is not from a class mentioned in
2610
         exclude_from_classes, for consistency */
2611
30
        if (trait == exclude_ce) {
2612
2
          zend_error_noreturn(E_COMPILE_ERROR,
2613
2
                 "Inconsistent insteadof definition. "
2614
2
                 "The method %s is to be used from %s, but %s is also on the exclude list",
2615
2
                 ZSTR_VAL(cur_method_ref->method_name),
2616
2
                 ZSTR_VAL(trait->name),
2617
2
                 ZSTR_VAL(trait->name));
2618
2
        }
2619
30
      }
2620
30
      zend_string_release_ex(lcname, 0);
2621
30
      i++;
2622
30
    }
2623
22
    ce->trait_precedences = precedences;
2624
22
  }
2625
2626
638
  if (ce->trait_aliases) {
2627
102
    i = 0;
2628
280
    while (ce->trait_aliases[i]) {
2629
178
      i++;
2630
178
    }
2631
102
    aliases = ecalloc(i, sizeof(zend_class_entry*));
2632
102
    i = 0;
2633
266
    while (ce->trait_aliases[i]) {
2634
178
      const zend_trait_alias *cur_alias = ce->trait_aliases[i];
2635
178
      cur_method_ref = &ce->trait_aliases[i]->trait_method;
2636
178
      lcname = zend_string_tolower(cur_method_ref->method_name);
2637
178
      if (cur_method_ref->class_name) {
2638
        /* For all aliases with an explicit class name, resolve the class now. */
2639
76
        lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2640
76
        trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2641
76
        zend_string_release_ex(lc_trait_name, 0);
2642
76
        if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2643
2
          zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2644
2
        }
2645
74
        zend_check_trait_usage(ce, trait, traits);
2646
74
        aliases[i] = trait;
2647
2648
        /* And, ensure that the referenced method is resolvable, too. */
2649
74
        if (!zend_hash_exists(&trait->function_table, lcname)) {
2650
4
          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
4
        }
2652
102
      } else {
2653
        /* Find out which trait this method refers to. */
2654
102
        trait = NULL;
2655
236
        for (j = 0; j < ce->num_traits; j++) {
2656
136
          if (traits[j]) {
2657
134
            if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2658
98
              if (!trait) {
2659
96
                trait = traits[j];
2660
96
                continue;
2661
96
              }
2662
2663
2
              zend_error_noreturn(E_COMPILE_ERROR,
2664
2
                "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
2
                ZSTR_VAL(cur_method_ref->method_name),
2666
2
                ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2667
2
                ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2668
2
                ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2669
98
            }
2670
134
          }
2671
136
        }
2672
2673
        /* Non-absolute method reference refers to method that does not exist. */
2674
100
        if (!trait) {
2675
6
          if (cur_alias->alias) {
2676
4
            zend_error_noreturn(E_COMPILE_ERROR,
2677
4
              "An alias (%s) was defined for method %s(), but this method does not exist",
2678
4
              ZSTR_VAL(cur_alias->alias),
2679
4
              ZSTR_VAL(cur_alias->trait_method.method_name));
2680
4
          } else {
2681
2
            zend_error_noreturn(E_COMPILE_ERROR,
2682
2
              "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2683
2
              ZSTR_VAL(cur_alias->trait_method.method_name));
2684
2
          }
2685
6
        }
2686
2687
94
        aliases[i] = trait;
2688
94
      }
2689
164
      zend_string_release_ex(lcname, 0);
2690
164
      i++;
2691
164
    }
2692
102
  }
2693
2694
624
  *exclude_tables_ptr = exclude_tables;
2695
624
  *aliases_ptr = aliases;
2696
624
}
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
686
{
2701
686
  uint32_t i;
2702
686
  zend_string *key;
2703
686
  zend_function *fn;
2704
2705
686
  if (exclude_tables) {
2706
52
    for (i = 0; i < ce->num_traits; i++) {
2707
36
      if (traits[i]) {
2708
        /* copies functions, applies defined aliasing, and excludes unused trait methods */
2709
192
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2710
192
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2711
192
          *contains_abstract_methods |= is_abstract;
2712
192
          if (verify_abstract != is_abstract) {
2713
0
            continue;
2714
0
          }
2715
60
          zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2716
60
        } ZEND_HASH_FOREACH_END();
2717
2718
36
        if (exclude_tables[i]) {
2719
20
          zend_hash_destroy(exclude_tables[i]);
2720
20
          FREE_HASHTABLE(exclude_tables[i]);
2721
20
          exclude_tables[i] = NULL;
2722
20
        }
2723
36
      }
2724
36
    }
2725
670
  } else {
2726
1.52k
    for (i = 0; i < ce->num_traits; i++) {
2727
852
      if (traits[i]) {
2728
3.64k
        ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2729
3.64k
          bool is_abstract = (bool) (fn->common.fn_flags & ZEND_ACC_ABSTRACT);
2730
3.64k
          *contains_abstract_methods |= is_abstract;
2731
3.64k
          if (verify_abstract != is_abstract) {
2732
210
            continue;
2733
210
          }
2734
760
          zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2735
760
        } ZEND_HASH_FOREACH_END();
2736
850
      }
2737
852
    }
2738
670
  }
2739
686
}
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
14
{
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
14
  if (colliding_ce == ce) {
2752
14
    for (size_t i = 0; i < current_trait; i++) {
2753
2
      if (traits[i]
2754
2
        && zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2755
2
        return traits[i];
2756
2
      }
2757
2
    }
2758
14
  }
2759
  /* Traits don't have it, then the composing class (or trait) itself has it. */
2760
12
  return colliding_ce;
2761
14
}
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
14
) {
2768
14
  zend_error_noreturn(E_COMPILE_ERROR,
2769
14
    "%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
14
    ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2771
14
    ZSTR_VAL(trait_constant->ce->name),
2772
14
    ZSTR_VAL(name),
2773
14
    ZSTR_VAL(ce->name)
2774
14
  );
2775
14
}
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
90
) {
2780
90
  uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2781
2782
90
  zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2783
90
  if (zv == NULL) {
2784
    /* No existing constant of the same name, so this one can be added */
2785
50
    return true;
2786
50
  }
2787
2788
40
  zend_class_constant *existing_constant = Z_PTR_P(zv);
2789
2790
40
  if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2791
4
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2792
4
    return false;
2793
4
  }
2794
2795
36
  if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) {
2796
2
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2797
2
    return false;
2798
34
  } else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2799
20
    inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2800
20
    inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2801
20
    if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
2802
4
      emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2803
4
      return false;
2804
4
    }
2805
20
  }
2806
2807
30
  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
4
    emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2810
4
    return false;
2811
4
  }
2812
2813
  /* There is an existing constant which is compatible with the new one, so no need to add it */
2814
26
  return false;
2815
30
}
2816
2817
static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2818
604
{
2819
1.34k
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2820
742
    zend_string *constant_name;
2821
742
    zend_class_constant *constant;
2822
2823
742
    if (!traits[i]) {
2824
2
      continue;
2825
2
    }
2826
2827
1.66k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2828
1.66k
      if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2829
50
        zend_class_constant *ct = NULL;
2830
2831
50
        ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2832
50
        memcpy(ct, constant, sizeof(zend_class_constant));
2833
50
        constant = ct;
2834
2835
50
        if (Z_TYPE(constant->value) == IS_CONSTANT_AST) {
2836
2
          ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2837
2
          ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2838
2
        }
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
50
        constant->ce = ce;
2845
2846
50
        Z_TRY_ADDREF(constant->value);
2847
50
        constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2848
50
        if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2849
0
          GC_ADDREF(constant->attributes);
2850
0
        }
2851
2852
50
        zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2853
50
      }
2854
1.66k
    } ZEND_HASH_FOREACH_END();
2855
740
  }
2856
604
}
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
16
{
2861
16
  if (colliding_ce == ce) {
2862
16
    for (size_t i = 0; i < current_trait; i++) {
2863
6
      if (traits[i]
2864
6
       && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2865
6
        return traits[i];
2866
6
      }
2867
6
    }
2868
16
  }
2869
2870
10
  return colliding_ce;
2871
16
}
2872
/* }}} */
2873
2874
static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2875
590
{
2876
590
  zend_property_info *property_info;
2877
590
  const zend_property_info *colliding_prop;
2878
590
  zend_string* prop_name;
2879
590
  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
1.29k
  for (uint32_t i = 0; i < ce->num_traits; i++) {
2887
726
    if (!traits[i]) {
2888
2
      continue;
2889
2
    }
2890
1.85k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2891
1.85k
      uint32_t flags = property_info->flags;
2892
2893
      /* next: check for conflicts with current class */
2894
1.85k
      if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2895
42
        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
42
        } else {
2899
42
          bool is_compatible = false;
2900
42
          uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2901
2902
42
          if (colliding_prop->hooks || property_info->hooks) {
2903
2
            zend_error_noreturn(E_COMPILE_ERROR,
2904
2
              "%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
2
              ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2906
2
              ZSTR_VAL(property_info->ce->name),
2907
2
              ZSTR_VAL(prop_name),
2908
2
              ZSTR_VAL(ce->name));
2909
2
          }
2910
2911
40
          if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2912
34
            verify_property_type_compatibility(property_info, colliding_prop, PROP_INVARIANT, false, false) == INHERITANCE_SUCCESS
2913
40
          ) {
2914
            /* the flags are identical, thus, the properties may be compatible */
2915
32
            zval *op1, *op2;
2916
2917
32
            if (flags & ZEND_ACC_STATIC) {
2918
2
              op1 = &ce->default_static_members_table[colliding_prop->offset];
2919
2
              op2 = &traits[i]->default_static_members_table[property_info->offset];
2920
2
              ZVAL_DEINDIRECT(op1);
2921
2
              ZVAL_DEINDIRECT(op2);
2922
30
            } else {
2923
30
              op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2924
30
              op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2925
30
            }
2926
32
            is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2927
32
          }
2928
2929
40
          if (!is_compatible) {
2930
14
            zend_error_noreturn(E_COMPILE_ERROR,
2931
14
                "%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
14
                ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2933
14
                ZSTR_VAL(property_info->ce->name),
2934
14
                ZSTR_VAL(prop_name),
2935
14
                ZSTR_VAL(ce->name));
2936
14
          }
2937
26
          if (!(flags & ZEND_ACC_STATIC)) {
2938
24
            continue;
2939
24
          }
2940
26
        }
2941
42
      }
2942
2943
162
      if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS) && !(property_info->flags & ZEND_ACC_READONLY)) {
2944
2
        zend_error_noreturn(E_COMPILE_ERROR,
2945
2
          "Readonly class %s cannot use trait with a non-readonly property %s::$%s",
2946
2
          ZSTR_VAL(ce->name),
2947
2
          ZSTR_VAL(property_info->ce->name),
2948
2
          ZSTR_VAL(prop_name)
2949
2
        );
2950
2
      }
2951
2952
      /* property not found, so lets add it */
2953
160
      zval tmp_prop_value;
2954
160
      if (!(flags & ZEND_ACC_VIRTUAL)) {
2955
150
        if (flags & ZEND_ACC_STATIC) {
2956
54
          prop_value = &traits[i]->default_static_members_table[property_info->offset];
2957
54
          ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2958
96
        } else {
2959
96
          prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2960
96
        }
2961
150
        Z_TRY_ADDREF_P(prop_value);
2962
150
      } else {
2963
10
        prop_value = &tmp_prop_value;
2964
10
        ZVAL_UNDEF(&tmp_prop_value);
2965
10
      }
2966
2967
160
      zend_string *doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2968
2969
160
      zend_type type = property_info->type;
2970
      /* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2971
160
      zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2972
160
      zend_property_info *new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2973
2974
160
      if (property_info->attributes) {
2975
4
        new_prop->attributes = property_info->attributes;
2976
2977
4
        if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2978
0
          GC_ADDREF(new_prop->attributes);
2979
0
        }
2980
4
      }
2981
160
      if (property_info->hooks) {
2982
12
        zend_function **hooks = new_prop->hooks =
2983
12
          zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2984
12
        memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2985
36
        for (uint32_t j = 0; j < ZEND_PROPERTY_HOOK_COUNT; j++) {
2986
24
          if (hooks[j]) {
2987
16
            zend_function *old_fn = hooks[j];
2988
2989
            /* Hooks are not yet supported for internal properties. */
2990
16
            ZEND_ASSERT(ZEND_USER_CODE(old_fn->type));
2991
2992
            /* Copy the function, because we need to adjust the scope. */
2993
16
            zend_function *new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2994
16
            memcpy(new_fn, old_fn, sizeof(zend_op_array));
2995
16
            new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2996
16
            new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2997
16
            new_fn->common.prop_info = new_prop;
2998
16
            function_add_ref(new_fn);
2999
3000
16
            zend_fixup_trait_method(new_fn, ce);
3001
3002
16
            hooks[j] = new_fn;
3003
16
          }
3004
24
        }
3005
12
        ce->num_hooked_props++;
3006
12
      }
3007
160
    } ZEND_HASH_FOREACH_END();
3008
724
  }
3009
590
}
3010
/* }}} */
3011
3012
122
#define MAX_ABSTRACT_INFO_CNT 3
3013
#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
3014
#define DISPLAY_ABSTRACT_FN(idx) \
3015
144
  ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
3016
144
  ai.afn[idx] ? "::" : "", \
3017
144
  ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
3018
144
  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
74
{
3027
74
  if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
3028
68
    ai->afn[ai->cnt] = fn;
3029
68
  }
3030
74
  ai->cnt++;
3031
74
}
3032
/* }}} */
3033
3034
void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
3035
82
{
3036
82
  const zend_function *func;
3037
82
  zend_abstract_info ai;
3038
82
  bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
3039
82
  bool can_be_abstract = (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_ANON_CLASS)) == 0;
3040
82
  memset(&ai, 0, sizeof(ai));
3041
3042
412
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
3043
412
    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
50
      if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
3047
42
        zend_verify_abstract_class_function(func, &ai);
3048
42
      }
3049
50
    }
3050
412
  } ZEND_HASH_FOREACH_END();
3051
3052
82
  if (!is_explicit_abstract) {
3053
46
    const zend_property_info *prop_info;
3054
118
    ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
3055
118
      if (prop_info->hooks) {
3056
84
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3057
56
          const zend_function *fn = prop_info->hooks[i];
3058
56
          if (fn && (fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3059
32
            zend_verify_abstract_class_function(fn, &ai);
3060
32
          }
3061
56
        }
3062
28
      }
3063
118
    } ZEND_HASH_FOREACH_END();
3064
46
  }
3065
3066
82
  if (ai.cnt) {
3067
48
    if (!is_explicit_abstract && can_be_abstract) {
3068
42
      zend_error_noreturn(E_ERROR,
3069
42
        "%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
42
        zend_get_object_type_uc(ce),
3071
42
        ZSTR_VAL(ce->name), ai.cnt,
3072
42
        ai.cnt > 1 ? "s" : "",
3073
42
        ai.cnt > 1 ? "s" : "",
3074
42
        DISPLAY_ABSTRACT_FN(0),
3075
42
        DISPLAY_ABSTRACT_FN(1),
3076
42
        DISPLAY_ABSTRACT_FN(2)
3077
42
      );
3078
42
    } else {
3079
6
      zend_error_noreturn(E_ERROR,
3080
6
        "%s %s must implement %d abstract method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3081
6
        zend_get_object_type_uc(ce),
3082
6
        ZSTR_VAL(ce->name), ai.cnt,
3083
6
        ai.cnt > 1 ? "s" : "",
3084
6
        DISPLAY_ABSTRACT_FN(0),
3085
6
        DISPLAY_ABSTRACT_FN(1),
3086
6
        DISPLAY_ABSTRACT_FN(2)
3087
6
      );
3088
6
    }
3089
48
  } else {
3090
    /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
3091
34
    ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3092
34
  }
3093
82
}
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
122
static void variance_obligation_dtor(zval *zv) {
3132
122
  efree(Z_PTR_P(zv));
3133
122
}
3134
3135
118
static void variance_obligation_ht_dtor(zval *zv) {
3136
118
  zend_hash_destroy(Z_PTR_P(zv));
3137
118
  FREE_HASHTABLE(Z_PTR_P(zv));
3138
118
}
3139
3140
122
static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
3141
122
  HashTable *ht;
3142
122
  zend_ulong key;
3143
122
  if (!CG(delayed_variance_obligations)) {
3144
94
    ALLOC_HASHTABLE(CG(delayed_variance_obligations));
3145
94
    zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
3146
94
  }
3147
3148
122
  key = (zend_ulong) (uintptr_t) ce;
3149
122
  ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
3150
122
  if (ht) {
3151
4
    return ht;
3152
4
  }
3153
3154
118
  ALLOC_HASHTABLE(ht);
3155
118
  zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
3156
118
  zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
3157
118
  ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
3158
118
  return ht;
3159
122
}
3160
3161
16
static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
3162
16
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3163
16
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3164
16
  obligation->type = OBLIGATION_DEPENDENCY;
3165
16
  obligation->dependency_ce = dependency_ce;
3166
16
  zend_hash_next_index_insert_ptr(obligations, obligation);
3167
16
}
3168
3169
static void add_compatibility_obligation(
3170
    zend_class_entry *ce,
3171
    const zend_function *child_fn, zend_class_entry *child_scope,
3172
82
    const zend_function *parent_fn, zend_class_entry *parent_scope) {
3173
82
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3174
82
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3175
82
  obligation->type = OBLIGATION_COMPATIBILITY;
3176
  /* Copy functions, because they may be stack-allocated in the case of traits. */
3177
82
  if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3178
0
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
3179
82
  } else {
3180
82
    memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
3181
82
  }
3182
82
  if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3183
6
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
3184
76
  } else {
3185
76
    memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
3186
76
  }
3187
82
  obligation->child_scope = child_scope;
3188
82
  obligation->parent_scope = parent_scope;
3189
82
  zend_hash_next_index_insert_ptr(obligations, obligation);
3190
82
}
3191
3192
static void add_property_compatibility_obligation(
3193
    zend_class_entry *ce, const zend_property_info *child_prop,
3194
22
    const zend_property_info *parent_prop, prop_variance variance) {
3195
22
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3196
22
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3197
22
  obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
3198
22
  obligation->child_prop = child_prop;
3199
22
  obligation->parent_prop = parent_prop;
3200
22
  obligation->variance = variance;
3201
22
  zend_hash_next_index_insert_ptr(obligations, obligation);
3202
22
}
3203
3204
static void add_class_constant_compatibility_obligation(
3205
    zend_class_entry *ce, const zend_class_constant *child_const,
3206
2
    const zend_class_constant *parent_const, const zend_string *const_name) {
3207
2
  HashTable *obligations = get_or_init_obligations_for_class(ce);
3208
2
  variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3209
2
  obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY;
3210
2
  obligation->const_name = const_name;
3211
2
  obligation->child_const = child_const;
3212
2
  obligation->parent_const = parent_const;
3213
2
  zend_hash_next_index_insert_ptr(obligations, obligation);
3214
2
}
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
108
static void check_variance_obligation(const variance_obligation *obligation) {
3229
108
  if (obligation->type == OBLIGATION_DEPENDENCY) {
3230
16
    zend_class_entry *dependency_ce = obligation->dependency_ce;
3231
16
    if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3232
14
      zend_class_entry *orig_linking_class = CG(current_linking_class);
3233
3234
14
      CG(current_linking_class) =
3235
14
        (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
3236
14
      resolve_delayed_variance_obligations(dependency_ce);
3237
14
      CG(current_linking_class) = orig_linking_class;
3238
14
    }
3239
92
  } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
3240
68
    inheritance_status status = zend_do_perform_implementation_check(
3241
68
      &obligation->child_fn, obligation->child_scope,
3242
68
      &obligation->parent_fn, obligation->parent_scope);
3243
68
    if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3244
48
      emit_incompatible_method_error(
3245
48
        &obligation->child_fn, obligation->child_scope,
3246
48
        &obligation->parent_fn, obligation->parent_scope, status);
3247
48
    }
3248
    /* Either the compatibility check was successful or only threw a warning. */
3249
68
  } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
3250
22
    verify_property_type_compatibility(obligation->parent_prop, obligation->child_prop, obligation->variance, true, true);
3251
22
  } else if (obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY) {
3252
2
    inheritance_status status =
3253
2
    class_constant_types_compatible(obligation->parent_const, obligation->child_const);
3254
2
    if (status != INHERITANCE_SUCCESS) {
3255
2
      emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name);
3256
2
    }
3257
2
  } 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
108
}
3266
3267
118
static void load_delayed_classes(const zend_class_entry *ce) {
3268
118
  HashTable *delayed_autoloads = CG(delayed_autoloads);
3269
118
  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
118
  HashPosition pos = 0;
3279
118
  zend_string *name;
3280
118
  zend_ulong idx;
3281
268
  while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
3282
268
      != HASH_KEY_NON_EXISTENT) {
3283
156
    zend_string_addref(name);
3284
156
    zend_hash_del(delayed_autoloads, name);
3285
156
    zend_lookup_class(name);
3286
156
    zend_string_release(name);
3287
156
    if (EG(exception)) {
3288
6
      zend_exception_uncaught_error(
3289
6
        "During inheritance of %s, while autoloading %s",
3290
6
        ZSTR_VAL(ce->name), ZSTR_VAL(name));
3291
6
    }
3292
156
  }
3293
118
}
3294
3295
104
static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
3296
104
  HashTable *all_obligations = CG(delayed_variance_obligations);
3297
104
  zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
3298
3299
104
  ZEND_ASSERT(all_obligations != NULL);
3300
104
  const HashTable *obligations = zend_hash_index_find_ptr(all_obligations, num_key);
3301
104
  ZEND_ASSERT(obligations != NULL);
3302
3303
104
  variance_obligation *obligation;
3304
320
  ZEND_HASH_FOREACH_PTR(obligations, obligation) {
3305
320
    check_variance_obligation(obligation);
3306
320
  } ZEND_HASH_FOREACH_END();
3307
3308
104
  zend_inheritance_check_override(ce);
3309
3310
104
  ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
3311
104
  ce->ce_flags |= ZEND_ACC_LINKED;
3312
104
  zend_hash_index_del(all_obligations, num_key);
3313
104
}
3314
3315
88
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
88
  if (CG(unlinked_uses)
3321
4
      && zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t)ce) == SUCCESS) {
3322
4
    zend_exception_uncaught_error(
3323
4
      "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
3324
4
  }
3325
88
}
3326
3327
23.6k
#define zend_update_inherited_handler(handler) do { \
3328
23.6k
    if (ce->handler == (zend_function*)op_array) { \
3329
511
      ce->handler = (zend_function*)new_op_array; \
3330
511
    } \
3331
23.6k
  } while (0)
3332
3333
static zend_op_array *zend_lazy_method_load(
3334
1.85k
    const zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3335
1.85k
  ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3336
1.85k
  ZEND_ASSERT(op_array->scope == pce);
3337
1.85k
  ZEND_ASSERT(op_array->prototype == NULL);
3338
1.85k
  zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3339
1.85k
  memcpy(new_op_array, op_array, sizeof(zend_op_array));
3340
1.85k
  new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3341
1.85k
  new_op_array->scope = ce;
3342
1.85k
  ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3343
1.85k
  ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3344
3345
1.85k
  return new_op_array;
3346
1.85k
}
3347
3348
static zend_class_entry *zend_lazy_class_load(const zend_class_entry *pce)
3349
2.48k
{
3350
2.48k
  zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3351
3352
2.48k
  memcpy(ce, pce, sizeof(zend_class_entry));
3353
2.48k
  ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3354
2.48k
  ce->refcount = 1;
3355
2.48k
  ce->inheritance_cache = NULL;
3356
2.48k
  if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3357
0
    ZEND_MAP_PTR_NEW(ce->mutable_data);
3358
2.48k
  } else {
3359
2.48k
    ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3360
2.48k
  }
3361
3362
  /* properties */
3363
2.48k
  if (ce->default_properties_table) {
3364
908
    zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3365
908
    zval *src = ce->default_properties_table;
3366
908
    const zval *end = src + ce->default_properties_count;
3367
3368
908
    ce->default_properties_table = dst;
3369
2.10k
    for (; src != end; src++, dst++) {
3370
1.19k
      ZVAL_COPY_VALUE_PROP(dst, src);
3371
1.19k
    }
3372
908
  }
3373
3374
  /* methods */
3375
2.48k
  ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3376
2.48k
  if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3377
964
    Bucket *p = emalloc(HT_SIZE(&ce->function_table));
3378
964
    memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3379
964
    HT_SET_DATA_ADDR(&ce->function_table, p);
3380
964
    p = ce->function_table.arData;
3381
964
    const Bucket *end = p + ce->function_table.nNumUsed;
3382
2.78k
    for (; p != end; p++) {
3383
1.82k
      zend_op_array *op_array = Z_PTR(p->val);
3384
1.82k
      zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3385
3386
1.82k
      zend_update_inherited_handler(constructor);
3387
1.82k
      zend_update_inherited_handler(destructor);
3388
1.82k
      zend_update_inherited_handler(clone);
3389
1.82k
      zend_update_inherited_handler(__get);
3390
1.82k
      zend_update_inherited_handler(__set);
3391
1.82k
      zend_update_inherited_handler(__call);
3392
1.82k
      zend_update_inherited_handler(__isset);
3393
1.82k
      zend_update_inherited_handler(__unset);
3394
1.82k
      zend_update_inherited_handler(__tostring);
3395
1.82k
      zend_update_inherited_handler(__callstatic);
3396
1.82k
      zend_update_inherited_handler(__debugInfo);
3397
1.82k
      zend_update_inherited_handler(__serialize);
3398
1.82k
      zend_update_inherited_handler(__unserialize);
3399
1.82k
    }
3400
964
  }
3401
3402
  /* static members */
3403
2.48k
  if (ce->default_static_members_table) {
3404
16
    zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
3405
16
    zval *src = ce->default_static_members_table;
3406
16
    const zval *end = src + ce->default_static_members_count;
3407
3408
16
    ce->default_static_members_table = dst;
3409
32
    for (; src != end; src++, dst++) {
3410
16
      ZVAL_COPY_VALUE(dst, src);
3411
16
    }
3412
16
  }
3413
2.48k
  ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3414
3415
  /* properties_info */
3416
2.48k
  if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3417
938
    Bucket *p = emalloc(HT_SIZE(&ce->properties_info));
3418
938
    memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3419
938
    HT_SET_DATA_ADDR(&ce->properties_info, p);
3420
938
    p = ce->properties_info.arData;
3421
938
    const Bucket *end = p + ce->properties_info.nNumUsed;
3422
2.17k
    for (; p != end; p++) {
3423
1.23k
      zend_property_info *new_prop_info;
3424
3425
1.23k
      const zend_property_info *prop_info = Z_PTR(p->val);
3426
1.23k
      ZEND_ASSERT(prop_info->ce == pce);
3427
1.23k
      ZEND_ASSERT(prop_info->prototype == prop_info);
3428
1.23k
      new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3429
1.23k
      Z_PTR(p->val) = new_prop_info;
3430
1.23k
      memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3431
1.23k
      new_prop_info->ce = ce;
3432
1.23k
      new_prop_info->prototype = new_prop_info;
3433
      /* Deep copy the type information */
3434
1.23k
      zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3435
1.23k
      if (new_prop_info->hooks) {
3436
26
        new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3437
26
        memcpy(new_prop_info->hooks, prop_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3438
78
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3439
52
          if (new_prop_info->hooks[i]) {
3440
28
            zend_op_array *hook = zend_lazy_method_load((zend_op_array *) new_prop_info->hooks[i], ce, pce);
3441
28
            ZEND_ASSERT(hook->prop_info == prop_info);
3442
28
            hook->prop_info = new_prop_info;
3443
28
            new_prop_info->ce = ce;
3444
28
            new_prop_info->hooks[i] = (zend_function *) hook;
3445
28
          }
3446
52
        }
3447
26
      }
3448
1.23k
    }
3449
938
  }
3450
3451
  /* constants table */
3452
2.48k
  if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3453
626
    Bucket *p = emalloc(HT_SIZE(&ce->constants_table));
3454
626
    memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3455
626
    HT_SET_DATA_ADDR(&ce->constants_table, p);
3456
626
    p = ce->constants_table.arData;
3457
626
    const Bucket *end = p + ce->constants_table.nNumUsed;
3458
1.63k
    for (; p != end; p++) {
3459
1.00k
      zend_class_constant *new_c;
3460
3461
1.00k
      const zend_class_constant *c = Z_PTR(p->val);
3462
1.00k
      ZEND_ASSERT(c->ce == pce);
3463
1.00k
      new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3464
1.00k
      Z_PTR(p->val) = new_c;
3465
1.00k
      memcpy(new_c, c, sizeof(zend_class_constant));
3466
1.00k
      new_c->ce = ce;
3467
1.00k
    }
3468
626
  }
3469
3470
2.48k
  return ce;
3471
2.48k
}
3472
3473
#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
3474
5.21k
# define UPDATE_IS_CACHEABLE(ce) do { \
3475
5.21k
      if ((ce)->type == ZEND_USER_CLASS) { \
3476
3.57k
        is_cacheable &= (ce)->ce_flags; \
3477
3.57k
      } \
3478
5.21k
    } 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
2.63k
{
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
2.63k
  zend_class_entry *parent = NULL;
3492
2.63k
  zend_class_entry **traits_and_interfaces = NULL;
3493
2.63k
  zend_class_entry *proto = NULL;
3494
2.63k
  zend_class_entry *orig_linking_class;
3495
2.63k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3496
2.63k
  uint32_t i, j;
3497
2.63k
  zval *zv;
3498
2.63k
  ALLOCA_FLAG(use_heap)
3499
3500
2.63k
  SET_ALLOCA_FLAG(use_heap);
3501
2.63k
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3502
3503
2.63k
  if (ce->parent_name) {
3504
566
    parent = zend_fetch_class_by_name(
3505
566
      ce->parent_name, lc_parent_name,
3506
566
      ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3507
566
    if (!parent) {
3508
50
      check_unrecoverable_load_failure(ce);
3509
50
      return NULL;
3510
50
    }
3511
516
    UPDATE_IS_CACHEABLE(parent);
3512
516
  }
3513
3514
2.58k
  if (ce->num_traits || ce->num_interfaces) {
3515
2.25k
    traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3516
3517
3.07k
    for (i = 0; i < ce->num_traits; i++) {
3518
844
      zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3519
844
        ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
3520
844
      if (UNEXPECTED(trait == NULL)) {
3521
20
        free_alloca(traits_and_interfaces, use_heap);
3522
20
        return NULL;
3523
20
      }
3524
824
      if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
3525
4
        zend_throw_error(NULL, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
3526
4
        free_alloca(traits_and_interfaces, use_heap);
3527
4
        return NULL;
3528
4
      }
3529
820
      if (UNEXPECTED(trait->ce_flags & ZEND_ACC_DEPRECATED)) {
3530
24
        zend_use_of_deprecated_trait(trait, ce->name);
3531
24
        if (UNEXPECTED(EG(exception))) {
3532
0
          free_alloca(traits_and_interfaces, use_heap);
3533
0
          return NULL;
3534
0
        }
3535
24
      }
3536
1.02k
      for (j = 0; j < i; j++) {
3537
210
        if (traits_and_interfaces[j] == trait) {
3538
          /* skip duplications */
3539
10
          trait = NULL;
3540
10
          break;
3541
10
        }
3542
210
      }
3543
820
      traits_and_interfaces[i] = trait;
3544
820
      if (trait) {
3545
810
        UPDATE_IS_CACHEABLE(trait);
3546
810
      }
3547
820
    }
3548
2.25k
  }
3549
3550
2.55k
  if (ce->num_interfaces) {
3551
3.70k
    for (i = 0; i < ce->num_interfaces; i++) {
3552
2.09k
      zend_class_entry *iface = zend_fetch_class_by_name(
3553
2.09k
        ce->interface_names[i].name, ce->interface_names[i].lc_name,
3554
2.09k
        ZEND_FETCH_CLASS_INTERFACE |
3555
2.09k
        ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3556
2.09k
      if (!iface) {
3557
38
        check_unrecoverable_load_failure(ce);
3558
38
        free_alloca(traits_and_interfaces, use_heap);
3559
38
        return NULL;
3560
38
      }
3561
2.05k
      traits_and_interfaces[ce->num_traits + i] = iface;
3562
2.05k
      if (iface) {
3563
2.05k
        UPDATE_IS_CACHEABLE(iface);
3564
2.05k
      }
3565
2.05k
    }
3566
1.64k
  }
3567
3568
2.51k
#ifndef ZEND_WIN32
3569
2.51k
  if (ce->ce_flags & ZEND_ACC_ENUM) {
3570
    /* We will add internal methods. */
3571
658
    is_cacheable = false;
3572
658
  }
3573
2.51k
#endif
3574
3575
2.51k
  if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3576
1.78k
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3577
1.78k
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3578
1.78k
      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
1.78k
    } else {
3587
0
      is_cacheable = 0;
3588
0
    }
3589
1.78k
    proto = ce;
3590
1.78k
  }
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
2.51k
  bool orig_record_errors = EG(record_errors);
3597
2.51k
  if (!orig_record_errors) {
3598
2.51k
    zend_begin_record_errors();
3599
2.51k
  }
3600
3601
2.51k
  zend_try {
3602
2.51k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3603
      /* Lazy class loading */
3604
2.47k
      ce = zend_lazy_class_load(ce);
3605
2.47k
      zv = zend_hash_find_known_hash(CG(class_table), key);
3606
2.47k
      Z_CE_P(zv) = ce;
3607
2.47k
    } 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
2.51k
    if (CG(unlinked_uses)) {
3616
24
      zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3617
24
    }
3618
3619
2.51k
    orig_linking_class = CG(current_linking_class);
3620
2.51k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3621
3622
2.51k
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3623
      /* Only register builtin enum methods during inheritance to avoid persisting them in
3624
       * opcache. */
3625
658
      zend_enum_register_funcs(ce);
3626
658
    }
3627
3628
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3629
    zend_link_hooked_object_iter(ce);
3630
#endif
3631
3632
2.51k
    HashTable **trait_exclude_tables;
3633
2.51k
    zend_class_entry **trait_aliases;
3634
2.51k
    bool trait_contains_abstract_methods = false;
3635
2.51k
    if (ce->num_traits) {
3636
648
      zend_traits_init_trait_structures(ce, traits_and_interfaces, &trait_exclude_tables, &trait_aliases);
3637
648
      zend_do_traits_method_binding(ce, traits_and_interfaces, trait_exclude_tables, trait_aliases, false, &trait_contains_abstract_methods);
3638
648
      zend_do_traits_constant_binding(ce, traits_and_interfaces);
3639
648
      zend_do_traits_property_binding(ce, traits_and_interfaces);
3640
3641
648
      zend_function *fn;
3642
3.00k
      ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3643
3.00k
        zend_fixup_trait_method(fn, ce);
3644
3.00k
      } ZEND_HASH_FOREACH_END();
3645
648
    }
3646
2.51k
    if (parent) {
3647
498
      if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3648
16
        add_dependency_obligation(ce, parent);
3649
16
      }
3650
498
      zend_do_inheritance(ce, parent);
3651
498
    }
3652
2.43k
    if (ce->num_traits) {
3653
568
      if (trait_contains_abstract_methods) {
3654
72
        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
72
        zend_function *fn;
3659
416
        ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
3660
416
          zend_fixup_trait_method(fn, ce);
3661
416
        } ZEND_HASH_FOREACH_END();
3662
72
      }
3663
3664
568
      if (trait_exclude_tables) {
3665
52
        for (i = 0; i < ce->num_traits; i++) {
3666
36
          if (traits_and_interfaces[i]) {
3667
36
            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
36
          }
3672
36
        }
3673
16
        efree(trait_exclude_tables);
3674
16
      }
3675
560
      if (trait_aliases) {
3676
82
        efree(trait_aliases);
3677
82
      }
3678
560
    }
3679
2.43k
    if (ce->num_interfaces) {
3680
      /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3681
1.60k
      uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3682
1.60k
      zend_class_entry **interfaces = emalloc(
3683
1.60k
          sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3684
3685
1.60k
      if (num_parent_interfaces) {
3686
30
        memcpy(interfaces, parent->interfaces,
3687
30
             sizeof(zend_class_entry *) * num_parent_interfaces);
3688
30
      }
3689
1.60k
      memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3690
1.60k
           sizeof(zend_class_entry *) * ce->num_interfaces);
3691
3692
1.60k
      zend_do_implement_interfaces(ce, interfaces);
3693
1.60k
    } else if (parent && parent->num_interfaces) {
3694
54
      zend_do_inherit_interfaces(ce, parent);
3695
54
    }
3696
2.42k
    if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3697
2.19k
      && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3698
2.42k
        ) {
3699
64
      zend_verify_abstract_class(ce);
3700
64
    }
3701
2.42k
    if (ce->ce_flags & ZEND_ACC_ENUM) {
3702
638
      zend_verify_enum(ce);
3703
638
    }
3704
2.42k
    if (ce->num_hooked_prop_variance_checks) {
3705
6
      const zend_property_info *prop_info;
3706
24
      ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
3707
24
        if (prop_info->ce == ce && prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
3708
6
          switch (zend_verify_property_hook_variance(prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
3709
4
            case INHERITANCE_SUCCESS:
3710
4
              break;
3711
2
            case INHERITANCE_ERROR:
3712
2
              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
6
          }
3720
6
        }
3721
24
      } ZEND_HASH_FOREACH_END();
3722
6
    }
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
2.42k
    if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3727
209
      && !zend_class_implements_interface(ce, zend_ce_stringable)) {
3728
6
      ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
3729
6
      ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
3730
6
      ce->num_interfaces++;
3731
6
      ce->interfaces = perealloc(ce->interfaces,
3732
6
                     sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
3733
6
      ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
3734
6
      do_interface_implementation(ce, zend_ce_stringable);
3735
6
    }
3736
3737
2.42k
    zend_build_properties_info_table(ce);
3738
2.42k
  } zend_catch {
3739
    /* Do not leak recorded errors to the next linked class. */
3740
264
    if (!orig_record_errors) {
3741
264
      EG(record_errors) = false;
3742
264
      zend_free_recorded_errors();
3743
264
    }
3744
6
    zend_bailout();
3745
2.42k
  } zend_end_try();
3746
3747
2.42k
  EG(record_errors) = orig_record_errors;
3748
3749
2.42k
  if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3750
2.13k
    zend_inheritance_check_override(ce);
3751
2.13k
    ce->ce_flags |= ZEND_ACC_LINKED;
3752
2.13k
  } else {
3753
296
    ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
3754
296
    if (CG(current_linking_class)) {
3755
98
      ce->ce_flags |= ZEND_ACC_CACHEABLE;
3756
98
    }
3757
296
    load_delayed_classes(ce);
3758
296
    if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3759
90
      resolve_delayed_variance_obligations(ce);
3760
90
    }
3761
296
    if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3762
4
      ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3763
292
    } else {
3764
292
      CG(current_linking_class) = NULL;
3765
292
    }
3766
296
  }
3767
3768
2.42k
  if (!CG(current_linking_class)) {
3769
676
    is_cacheable = 0;
3770
676
  }
3771
2.42k
  CG(current_linking_class) = orig_linking_class;
3772
3773
2.42k
  if (is_cacheable) {
3774
1.46k
    HashTable *ht = (HashTable*)ce->inheritance_cache;
3775
1.46k
    zend_class_entry *new_ce;
3776
3777
1.46k
    ce->inheritance_cache = NULL;
3778
1.46k
    new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3779
1.46k
    if (new_ce) {
3780
1.46k
      zv = zend_hash_find_known_hash(CG(class_table), key);
3781
1.46k
      ce = new_ce;
3782
1.46k
      Z_CE_P(zv) = ce;
3783
1.46k
    }
3784
1.46k
    if (ht) {
3785
50
      zend_hash_destroy(ht);
3786
50
      FREE_HASHTABLE(ht);
3787
50
    }
3788
1.46k
  }
3789
3790
2.42k
  if (!orig_record_errors) {
3791
2.14k
    zend_emit_recorded_errors();
3792
2.14k
    zend_free_recorded_errors();
3793
2.14k
  }
3794
2.42k
  if (traits_and_interfaces) {
3795
1.94k
    free_alloca(traits_and_interfaces, use_heap);
3796
1.94k
  }
3797
3798
2.42k
  if (ZSTR_HAS_CE_CACHE(ce->name)) {
3799
2.06k
    ZSTR_SET_CE_CACHE(ce->name, ce);
3800
2.06k
  }
3801
3802
2.42k
  return ce;
3803
2.42k
}
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
1.83k
{
3809
1.83k
  zend_string *key;
3810
1.83k
  zend_function *parent_func;
3811
1.83k
  const zend_property_info *parent_info;
3812
1.83k
  const zend_class_constant *parent_const;
3813
1.83k
  inheritance_status overall_status = INHERITANCE_SUCCESS;
3814
3815
11.0k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3816
11.0k
    zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3817
11.0k
    if (zv) {
3818
798
      zend_function *child_func = Z_FUNC_P(zv);
3819
798
      inheritance_status status =
3820
798
        do_inheritance_check_on_method(
3821
798
          child_func, child_func->common.scope,
3822
798
          parent_func, parent_func->common.scope,
3823
798
          ce, NULL,
3824
798
          ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3825
798
      if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3826
18
        overall_status = INHERITANCE_WARNING;
3827
780
      } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3828
208
        return status;
3829
208
      }
3830
798
    }
3831
11.0k
  } ZEND_HASH_FOREACH_END();
3832
3833
6.75k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3834
6.75k
    const zval *zv;
3835
6.75k
    if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3836
1.17k
      continue;
3837
1.17k
    }
3838
3839
578
    zv = zend_hash_find_known_hash(&ce->properties_info, key);
3840
578
    if (zv) {
3841
232
      const zend_property_info *child_info = Z_PTR_P(zv);
3842
232
      if (ZEND_TYPE_IS_SET(child_info->type)) {
3843
224
        inheritance_status status = verify_property_type_compatibility(parent_info, child_info, prop_get_variance(parent_info), false, false);
3844
224
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3845
96
          return status;
3846
96
        }
3847
224
      }
3848
232
    }
3849
578
  } ZEND_HASH_FOREACH_END();
3850
3851
4.07k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3852
4.07k
    const zval *zv;
3853
4.07k
    if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3854
184
      continue;
3855
184
    }
3856
3857
322
    zv = zend_hash_find_known_hash(&ce->constants_table, key);
3858
322
    if (zv) {
3859
18
      const zend_class_constant *child_const = Z_PTR_P(zv);
3860
18
      if (ZEND_TYPE_IS_SET(child_const->type)) {
3861
16
        inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3862
16
        ZEND_ASSERT(status != INHERITANCE_WARNING);
3863
16
        if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3864
10
          return status;
3865
10
        }
3866
16
      }
3867
18
    }
3868
322
  } ZEND_HASH_FOREACH_END();
3869
3870
1.51k
  return overall_status;
3871
1.52k
}
3872
/* }}} */
3873
3874
1.65k
static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3875
1.65k
  if (delayed_early_binding) {
3876
14
    if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3877
14
      if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3878
14
        Z_CE_P(delayed_early_binding) = ce;
3879
14
        return true;
3880
14
      }
3881
14
    } 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
1.64k
  if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3893
1.63k
    return true;
3894
1.63k
  }
3895
6
  return false;
3896
1.64k
}
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
1.83k
{
3900
1.83k
  inheritance_status status;
3901
1.83k
  zend_class_entry *proto = NULL;
3902
1.83k
  zend_class_entry *orig_linking_class;
3903
3904
1.83k
  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
1.83k
  uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3914
1.83k
  UPDATE_IS_CACHEABLE(parent_ce);
3915
1.83k
  if (is_cacheable) {
3916
100
    if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3917
100
      zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3918
100
      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
100
    } else {
3926
0
      is_cacheable = 0;
3927
0
    }
3928
100
    proto = ce;
3929
100
  }
3930
3931
1.83k
  orig_linking_class = CG(current_linking_class);
3932
1.83k
  CG(current_linking_class) = NULL;
3933
1.83k
  status = zend_can_early_bind(ce, parent_ce);
3934
1.83k
  CG(current_linking_class) = orig_linking_class;
3935
1.83k
  if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3936
1.65k
    if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3937
      /* Lazy class loading */
3938
14
      ce = zend_lazy_class_load(ce);
3939
1.64k
    } 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
1.65k
    if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3946
6
      return NULL;
3947
6
    }
3948
3949
1.64k
    orig_linking_class = CG(current_linking_class);
3950
1.64k
    CG(current_linking_class) = is_cacheable ? ce : NULL;
3951
3952
1.64k
    bool orig_record_errors = EG(record_errors);
3953
3954
1.64k
    zend_try{
3955
1.64k
      CG(zend_lineno) = ce->info.user.line_start;
3956
3957
1.64k
      if (!orig_record_errors) {
3958
38
        zend_begin_record_errors();
3959
38
      }
3960
3961
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3962
      zend_link_hooked_object_iter(ce);
3963
#endif
3964
3965
1.64k
      zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3966
1.64k
      if (parent_ce && parent_ce->num_interfaces) {
3967
116
        zend_do_inherit_interfaces(ce, parent_ce);
3968
116
      }
3969
1.64k
      zend_build_properties_info_table(ce);
3970
1.64k
      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
12
        zend_verify_abstract_class(ce);
3972
12
      }
3973
1.64k
      zend_inheritance_check_override(ce);
3974
1.64k
      ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3975
1.64k
      ce->ce_flags |= ZEND_ACC_LINKED;
3976
3977
1.44k
      CG(current_linking_class) = orig_linking_class;
3978
1.44k
    } zend_catch {
3979
2
      if (!orig_record_errors) {
3980
2
        EG(record_errors) = false;
3981
2
        zend_free_recorded_errors();
3982
2
      }
3983
0
      zend_bailout();
3984
1.44k
    } zend_end_try();
3985
3986
1.44k
    if (is_cacheable) {
3987
12
      HashTable *ht = (HashTable*)ce->inheritance_cache;
3988
12
      zend_class_entry *new_ce;
3989
3990
12
      ce->inheritance_cache = NULL;
3991
12
      new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3992
12
      if (new_ce) {
3993
12
        zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3994
12
        ce = new_ce;
3995
12
        Z_CE_P(zv) = ce;
3996
12
      }
3997
12
      if (ht) {
3998
0
        zend_hash_destroy(ht);
3999
0
        FREE_HASHTABLE(ht);
4000
0
      }
4001
12
    }
4002
4003
1.44k
    if (!orig_record_errors) {
4004
36
      zend_emit_recorded_errors();
4005
36
      zend_free_recorded_errors();
4006
36
    }
4007
4008
1.44k
    if (ZSTR_HAS_CE_CACHE(ce->name)) {
4009
1.33k
      ZSTR_SET_CE_CACHE(ce->name, ce);
4010
1.33k
    }
4011
1.44k
    zend_observer_class_linked_notify(ce, lcname);
4012
4013
1.44k
    return ce;
4014
1.44k
  }
4015
178
  return NULL;
4016
1.83k
}
4017
/* }}} */