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_smart_str.h"
27 #include "zend_operators.h"
28 #include "zend_exceptions.h"
29 #include "zend_enum.h"
30 #include "zend_attributes.h"
31 #include "zend_constants.h"
32
33 ZEND_API zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces) = NULL;
34 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;
35
36 /* Unresolved means that class declarations that are currently not available are needed to
37 * determine whether the inheritance is valid or not. At runtime UNRESOLVED should be treated
38 * as an ERROR. */
39 typedef enum {
40 INHERITANCE_UNRESOLVED = -1,
41 INHERITANCE_ERROR = 0,
42 INHERITANCE_WARNING = 1,
43 INHERITANCE_SUCCESS = 2,
44 } inheritance_status;
45
46 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce);
47 static void add_compatibility_obligation(
48 zend_class_entry *ce, const zend_function *child_fn, zend_class_entry *child_scope,
49 const zend_function *parent_fn, zend_class_entry *parent_scope);
50 static void add_property_compatibility_obligation(
51 zend_class_entry *ce, const zend_property_info *child_prop,
52 const zend_property_info *parent_prop);
53
54 static void ZEND_COLD emit_incompatible_method_error(
55 const zend_function *child, zend_class_entry *child_scope,
56 const zend_function *parent, zend_class_entry *parent_scope,
57 inheritance_status status);
58
zend_type_copy_ctor(zend_type * type,bool persistent)59 static void zend_type_copy_ctor(zend_type *type, bool persistent) {
60 if (ZEND_TYPE_HAS_LIST(*type)) {
61 zend_type_list *old_list = ZEND_TYPE_LIST(*type);
62 size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
63 zend_type_list *new_list = ZEND_TYPE_USES_ARENA(*type)
64 ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
65 memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types));
66 ZEND_TYPE_SET_PTR(*type, new_list);
67
68 zend_type *list_type;
69 ZEND_TYPE_LIST_FOREACH(new_list, list_type) {
70 ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
71 zend_string_addref(ZEND_TYPE_NAME(*list_type));
72 } ZEND_TYPE_LIST_FOREACH_END();
73 } else if (ZEND_TYPE_HAS_NAME(*type)) {
74 zend_string_addref(ZEND_TYPE_NAME(*type));
75 }
76 }
77
zend_duplicate_internal_function(zend_function * func,zend_class_entry * ce)78 static zend_function *zend_duplicate_internal_function(zend_function *func, zend_class_entry *ce) /* {{{ */
79 {
80 zend_function *new_function;
81
82 if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
83 new_function = pemalloc(sizeof(zend_internal_function), 1);
84 memcpy(new_function, func, sizeof(zend_internal_function));
85 } else {
86 new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
87 memcpy(new_function, func, sizeof(zend_internal_function));
88 new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
89 }
90 if (EXPECTED(new_function->common.function_name)) {
91 zend_string_addref(new_function->common.function_name);
92 }
93 return new_function;
94 }
95 /* }}} */
96
zend_duplicate_function(zend_function * func,zend_class_entry * ce)97 static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, zend_class_entry *ce) /* {{{ */
98 {
99 if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
100 return zend_duplicate_internal_function(func, ce);
101 } else {
102 if (func->op_array.refcount) {
103 (*func->op_array.refcount)++;
104 }
105 if (EXPECTED(func->op_array.function_name)) {
106 zend_string_addref(func->op_array.function_name);
107 }
108 return func;
109 }
110 }
111 /* }}} */
112
do_inherit_parent_constructor(zend_class_entry * ce)113 static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
114 {
115 zend_class_entry *parent = ce->parent;
116
117 ZEND_ASSERT(parent != NULL);
118
119 /* You cannot change create_object */
120 ce->create_object = parent->create_object;
121
122 /* Inherit special functions if needed */
123 if (EXPECTED(!ce->get_iterator)) {
124 ce->get_iterator = parent->get_iterator;
125 }
126 if (EXPECTED(!ce->__get)) {
127 ce->__get = parent->__get;
128 }
129 if (EXPECTED(!ce->__set)) {
130 ce->__set = parent->__set;
131 }
132 if (EXPECTED(!ce->__unset)) {
133 ce->__unset = parent->__unset;
134 }
135 if (EXPECTED(!ce->__isset)) {
136 ce->__isset = parent->__isset;
137 }
138 if (EXPECTED(!ce->__call)) {
139 ce->__call = parent->__call;
140 }
141 if (EXPECTED(!ce->__callstatic)) {
142 ce->__callstatic = parent->__callstatic;
143 }
144 if (EXPECTED(!ce->__tostring)) {
145 ce->__tostring = parent->__tostring;
146 }
147 if (EXPECTED(!ce->clone)) {
148 ce->clone = parent->clone;
149 }
150 if (EXPECTED(!ce->__serialize)) {
151 ce->__serialize = parent->__serialize;
152 }
153 if (EXPECTED(!ce->__unserialize)) {
154 ce->__unserialize = parent->__unserialize;
155 }
156 if (EXPECTED(!ce->serialize)) {
157 ce->serialize = parent->serialize;
158 }
159 if (EXPECTED(!ce->unserialize)) {
160 ce->unserialize = parent->unserialize;
161 }
162 if (!ce->destructor) {
163 ce->destructor = parent->destructor;
164 }
165 if (EXPECTED(!ce->__debugInfo)) {
166 ce->__debugInfo = parent->__debugInfo;
167 }
168
169 if (ce->constructor) {
170 if (parent->constructor && UNEXPECTED(parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) {
171 zend_error_noreturn(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
172 ZSTR_VAL(parent->name), ZSTR_VAL(parent->constructor->common.function_name),
173 ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
174 }
175 return;
176 }
177
178 ce->constructor = parent->constructor;
179 }
180 /* }}} */
181
zend_visibility_string(uint32_t fn_flags)182 char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
183 {
184 if (fn_flags & ZEND_ACC_PUBLIC) {
185 return "public";
186 } else if (fn_flags & ZEND_ACC_PRIVATE) {
187 return "private";
188 } else {
189 ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
190 return "protected";
191 }
192 }
193 /* }}} */
194
resolve_class_name(zend_class_entry * scope,zend_string * name)195 static zend_string *resolve_class_name(zend_class_entry *scope, zend_string *name) {
196 ZEND_ASSERT(scope);
197 if (zend_string_equals_literal_ci(name, "parent") && scope->parent) {
198 if (scope->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
199 return scope->parent->name;
200 } else {
201 return scope->parent_name;
202 }
203 } else if (zend_string_equals_literal_ci(name, "self")) {
204 return scope->name;
205 } else {
206 return name;
207 }
208 }
209
class_visible(zend_class_entry * ce)210 static bool class_visible(zend_class_entry *ce) {
211 if (ce->type == ZEND_INTERNAL_CLASS) {
212 return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
213 } else {
214 ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
215 return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
216 || ce->info.user.filename == CG(compiled_filename);
217 }
218 }
219
register_unresolved_class(zend_string * name)220 static zend_always_inline void register_unresolved_class(zend_string *name) {
221 /* We'll autoload this class and process delayed variance obligations later. */
222 if (!CG(delayed_autoloads)) {
223 ALLOC_HASHTABLE(CG(delayed_autoloads));
224 zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
225 }
226 zend_hash_add_empty_element(CG(delayed_autoloads), name);
227 }
228
lookup_class_ex(zend_class_entry * scope,zend_string * name,bool register_unresolved)229 static zend_class_entry *lookup_class_ex(
230 zend_class_entry *scope, zend_string *name, bool register_unresolved) {
231 zend_class_entry *ce;
232 bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
233
234 if (UNEXPECTED(!EG(active) && !in_preload)) {
235 zend_string *lc_name = zend_string_tolower(name);
236
237 ce = zend_hash_find_ptr(CG(class_table), lc_name);
238
239 zend_string_release(lc_name);
240
241 if (register_unresolved && !ce) {
242 zend_error_noreturn(
243 E_COMPILE_ERROR, "%s must be registered before %s",
244 ZSTR_VAL(name), ZSTR_VAL(scope->name));
245 }
246
247 return ce;
248 }
249
250 ce = zend_lookup_class_ex(
251 name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
252
253 if (!CG(in_compilation) || in_preload) {
254 if (ce) {
255 return ce;
256 }
257
258 if (register_unresolved) {
259 register_unresolved_class(name);
260 }
261 } else {
262 if (ce && class_visible(ce)) {
263 return ce;
264 }
265
266 /* The current class may not be registered yet, so check for it explicitly. */
267 if (zend_string_equals_ci(scope->name, name)) {
268 return scope;
269 }
270 }
271
272 return NULL;
273 }
274
lookup_class(zend_class_entry * scope,zend_string * name)275 static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name) {
276 return lookup_class_ex(scope, name, /* register_unresolved */ false);
277 }
278
279 /* Instanceof that's safe to use on unlinked classes. */
unlinked_instanceof(zend_class_entry * ce1,zend_class_entry * ce2)280 static bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) {
281 if (ce1 == ce2) {
282 return 1;
283 }
284
285 if (ce1->ce_flags & ZEND_ACC_LINKED) {
286 return instanceof_function(ce1, ce2);
287 }
288
289 if (ce1->parent) {
290 zend_class_entry *parent_ce;
291 if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
292 parent_ce = ce1->parent;
293 } else {
294 parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
295 ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
296 }
297
298 /* It's not sufficient to only check the parent chain itself, as need to do a full
299 * recursive instanceof in case the parent interfaces haven't been copied yet. */
300 if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
301 return 1;
302 }
303 }
304
305 if (ce1->num_interfaces) {
306 uint32_t i;
307 if (ce1->ce_flags & ZEND_ACC_RESOLVED_INTERFACES) {
308 /* Unlike the normal instanceof_function(), we have to perform a recursive
309 * check here, as the parent interfaces might not have been fully copied yet. */
310 for (i = 0; i < ce1->num_interfaces; i++) {
311 if (unlinked_instanceof(ce1->interfaces[i], ce2)) {
312 return 1;
313 }
314 }
315 } else {
316 for (i = 0; i < ce1->num_interfaces; i++) {
317 zend_class_entry *ce = zend_lookup_class_ex(
318 ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
319 ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
320 /* Avoid recursing if class implements itself. */
321 if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
322 return 1;
323 }
324 }
325 }
326 }
327
328 return 0;
329 }
330
zend_type_contains_traversable(zend_type type)331 static bool zend_type_contains_traversable(zend_type type) {
332 zend_type *single_type;
333 if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
334 return 1;
335 }
336
337 ZEND_TYPE_FOREACH(type, single_type) {
338 if (ZEND_TYPE_HAS_NAME(*single_type)
339 && zend_string_equals_literal_ci(ZEND_TYPE_NAME(*single_type), "Traversable")) {
340 return 1;
341 }
342 } ZEND_TYPE_FOREACH_END();
343 return 0;
344 }
345
zend_type_permits_self(zend_type type,zend_class_entry * scope,zend_class_entry * self)346 static bool zend_type_permits_self(
347 zend_type type, zend_class_entry *scope, zend_class_entry *self) {
348 if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
349 return 1;
350 }
351
352 /* Any types that may satisfy self must have already been loaded at this point
353 * (as a parent or interface), so we never need to register delayed variance obligations
354 * for this case. */
355 zend_type *single_type;
356 ZEND_TYPE_FOREACH(type, single_type) {
357 if (ZEND_TYPE_HAS_NAME(*single_type)) {
358 zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
359 zend_class_entry *ce = lookup_class(self, name);
360 if (ce && unlinked_instanceof(self, ce)) {
361 return 1;
362 }
363 }
364 } ZEND_TYPE_FOREACH_END();
365 return 0;
366 }
367
track_class_dependency(zend_class_entry * ce,zend_string * class_name)368 static void track_class_dependency(zend_class_entry *ce, zend_string *class_name)
369 {
370 HashTable *ht;
371
372 if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
373 return;
374 } else if (!class_name) {
375 class_name = ce->name;
376 } else if (zend_string_equals_literal_ci(class_name, "self")
377 || zend_string_equals_literal_ci(class_name, "parent")) {
378 return;
379 }
380
381 #ifndef ZEND_WIN32
382 /* On non-Windows systems, internal classes are always the same,
383 * so there is no need to explicitly track them. */
384 if (ce->type == ZEND_INTERNAL_CLASS) {
385 return;
386 }
387 #endif
388
389 ht = (HashTable*)CG(current_linking_class)->inheritance_cache;
390
391 if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
392 // TODO: dependency on not-immutable class ???
393 if (ht) {
394 zend_hash_destroy(ht);
395 FREE_HASHTABLE(ht);
396 CG(current_linking_class)->inheritance_cache = NULL;
397 }
398 CG(current_linking_class)->ce_flags &= ~ZEND_ACC_CACHEABLE;
399 CG(current_linking_class) = NULL;
400 return;
401 }
402
403 /* Record dependency */
404 if (!ht) {
405 ALLOC_HASHTABLE(ht);
406 zend_hash_init(ht, 0, NULL, NULL, 0);
407 CG(current_linking_class)->inheritance_cache = (zend_inheritance_cache_entry*)ht;
408 }
409 zend_hash_add_ptr(ht, class_name, ce);
410 }
411
412 /* Check whether any type in the fe_type intersection type is a subtype of the proto class. */
zend_is_intersection_subtype_of_class(zend_class_entry * fe_scope,zend_type fe_type,zend_class_entry * proto_scope,zend_string * proto_class_name,zend_class_entry * proto_ce)413 static inheritance_status zend_is_intersection_subtype_of_class(
414 zend_class_entry *fe_scope, zend_type fe_type,
415 zend_class_entry *proto_scope, zend_string *proto_class_name, zend_class_entry *proto_ce)
416 {
417 ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(fe_type));
418 bool have_unresolved = false;
419 zend_type *single_type;
420
421 /* Traverse the list of child types and check that at least one is
422 * a subtype of the parent type being checked */
423 ZEND_TYPE_FOREACH(fe_type, single_type) {
424 zend_class_entry *fe_ce;
425 zend_string *fe_class_name = NULL;
426 if (ZEND_TYPE_HAS_NAME(*single_type)) {
427 fe_class_name =
428 resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
429 if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
430 return INHERITANCE_SUCCESS;
431 }
432
433 if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
434 fe_ce = lookup_class(fe_scope, fe_class_name);
435 } else {
436 /* standard type in an intersection type is impossible,
437 * because it would be a fatal compile error */
438 ZEND_UNREACHABLE();
439 continue;
440 }
441
442 if (!fe_ce || !proto_ce) {
443 have_unresolved = true;
444 continue;
445 }
446 if (unlinked_instanceof(fe_ce, proto_ce)) {
447 track_class_dependency(fe_ce, fe_class_name);
448 track_class_dependency(proto_ce, proto_class_name);
449 return INHERITANCE_SUCCESS;
450 }
451 } ZEND_TYPE_FOREACH_END();
452
453 return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
454 }
455
456 /* Check whether a single class proto type is a subtype of a potentially complex fe_type. */
zend_is_class_subtype_of_type(zend_class_entry * fe_scope,zend_string * fe_class_name,zend_class_entry * proto_scope,zend_type proto_type)457 static inheritance_status zend_is_class_subtype_of_type(
458 zend_class_entry *fe_scope, zend_string *fe_class_name,
459 zend_class_entry *proto_scope, zend_type proto_type) {
460 zend_class_entry *fe_ce = NULL;
461 bool have_unresolved = 0;
462
463 /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
464 if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_OBJECT) {
465 /* Currently, any class name would be allowed here. We still perform a class lookup
466 * for forward-compatibility reasons, as we may have named types in the future that
467 * are not classes (such as typedefs). */
468 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
469 if (!fe_ce) {
470 have_unresolved = 1;
471 } else {
472 track_class_dependency(fe_ce, fe_class_name);
473 return INHERITANCE_SUCCESS;
474 }
475 }
476 if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_ITERABLE) {
477 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
478 if (!fe_ce) {
479 have_unresolved = 1;
480 } else if (unlinked_instanceof(fe_ce, zend_ce_traversable)) {
481 track_class_dependency(fe_ce, fe_class_name);
482 return INHERITANCE_SUCCESS;
483 }
484 }
485
486 zend_type *single_type;
487
488 /* Traverse the list of parent types and check if the current child (FE)
489 * class is the subtype of at least one of them (union) or all of them (intersection). */
490 bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
491 ZEND_TYPE_FOREACH(proto_type, single_type) {
492 zend_class_entry *proto_ce;
493 zend_string *proto_class_name = NULL;
494 if (ZEND_TYPE_HAS_NAME(*single_type)) {
495 proto_class_name =
496 resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
497 if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
498 if (!is_intersection) {
499 return INHERITANCE_SUCCESS;
500 }
501 continue;
502 }
503
504 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
505 proto_ce = lookup_class(proto_scope, proto_class_name);
506 } else {
507 /* standard type */
508 ZEND_ASSERT(!is_intersection);
509 continue;
510 }
511
512 if (!fe_ce || !proto_ce) {
513 have_unresolved = 1;
514 continue;
515 }
516 if (unlinked_instanceof(fe_ce, proto_ce)) {
517 track_class_dependency(fe_ce, fe_class_name);
518 track_class_dependency(proto_ce, proto_class_name);
519 if (!is_intersection) {
520 return INHERITANCE_SUCCESS;
521 }
522 } else {
523 if (is_intersection) {
524 return INHERITANCE_ERROR;
525 }
526 }
527 } ZEND_TYPE_FOREACH_END();
528
529 if (have_unresolved) {
530 return INHERITANCE_UNRESOLVED;
531 }
532 return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
533 }
534
get_class_from_type(zend_class_entry * scope,zend_type single_type)535 static zend_string *get_class_from_type(zend_class_entry *scope, zend_type single_type) {
536 if (ZEND_TYPE_HAS_NAME(single_type)) {
537 return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
538 }
539 return NULL;
540 }
541
register_unresolved_classes(zend_class_entry * scope,zend_type type)542 static void register_unresolved_classes(zend_class_entry *scope, zend_type type) {
543 zend_type *single_type;
544 ZEND_TYPE_FOREACH(type, single_type) {
545 if (ZEND_TYPE_HAS_NAME(*single_type)) {
546 zend_string *class_name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
547 lookup_class_ex(scope, class_name, /* register_unresolved */ true);
548 }
549 } ZEND_TYPE_FOREACH_END();
550 }
551
zend_perform_covariant_type_check(zend_class_entry * fe_scope,zend_type fe_type,zend_class_entry * proto_scope,zend_type proto_type)552 static inheritance_status zend_perform_covariant_type_check(
553 zend_class_entry *fe_scope, zend_type fe_type,
554 zend_class_entry *proto_scope, zend_type proto_type)
555 {
556 ZEND_ASSERT(ZEND_TYPE_IS_SET(fe_type) && ZEND_TYPE_IS_SET(proto_type));
557
558 /* Apart from void, everything is trivially covariant to the mixed type.
559 * Handle this case separately to ensure it never requires class loading. */
560 if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
561 !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
562 return INHERITANCE_SUCCESS;
563 }
564
565 /* Builtin types may be removed, but not added */
566 uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
567 uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
568 uint32_t added_types = fe_type_mask & ~proto_type_mask;
569 if (added_types) {
570 // TODO: Make "iterable" an alias of "array|Traversable" instead,
571 // so these special cases will be handled automatically.
572 if ((added_types & MAY_BE_ITERABLE)
573 && (proto_type_mask & MAY_BE_ARRAY)
574 && zend_type_contains_traversable(proto_type)) {
575 /* Replacing array|Traversable with iterable is okay */
576 added_types &= ~MAY_BE_ITERABLE;
577 }
578 if ((added_types & MAY_BE_ARRAY) && (proto_type_mask & MAY_BE_ITERABLE)) {
579 /* Replacing iterable with array is okay */
580 added_types &= ~MAY_BE_ARRAY;
581 }
582 if ((added_types & MAY_BE_STATIC)
583 && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
584 /* Replacing type that accepts self with static is okay */
585 added_types &= ~MAY_BE_STATIC;
586 }
587
588 if (added_types == MAY_BE_NEVER) {
589 /* never is the bottom type */
590 return INHERITANCE_SUCCESS;
591 }
592
593 if (added_types) {
594 /* Otherwise adding new types is illegal */
595 return INHERITANCE_ERROR;
596 }
597 }
598
599 zend_type *single_type;
600 inheritance_status early_exit_status;
601 bool have_unresolved = false;
602
603 if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
604 /* Currently, for object type any class name would be allowed here.
605 * We still perform a class lookup for forward-compatibility reasons,
606 * as we may have named types in the future that are not classes
607 * (such as typedefs). */
608 if (proto_type_mask & (MAY_BE_OBJECT|MAY_BE_ITERABLE)) {
609 bool any_class = (proto_type_mask & MAY_BE_OBJECT) != 0;
610 ZEND_TYPE_FOREACH(fe_type, single_type) {
611 zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
612 if (!fe_class_name) {
613 continue;
614 }
615 zend_class_entry *fe_ce = lookup_class(fe_scope, fe_class_name);
616 if (fe_ce) {
617 if (any_class || unlinked_instanceof(fe_ce, zend_ce_traversable)) {
618 track_class_dependency(fe_ce, fe_class_name);
619 return INHERITANCE_SUCCESS;
620 }
621 } else {
622 have_unresolved = true;
623 }
624 } ZEND_TYPE_FOREACH_END();
625 }
626
627 /* U_1&...&U_n < V_1&...&V_m if forall V_j. exists U_i. U_i < V_j.
628 * U_1&...&U_n < V_1|...|V_m if exists V_j. exists U_i. U_i < V_j.
629 * As such, we need to iterate over proto_type (V_j) first and use a different
630 * quantifier depending on whether fe_type is a union or an intersection. */
631 early_exit_status =
632 ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
633 ZEND_TYPE_FOREACH(proto_type, single_type) {
634 zend_string *proto_class_name = get_class_from_type(proto_scope, *single_type);
635 if (!proto_class_name) {
636 continue;
637 }
638
639 zend_class_entry *proto_ce = NULL;
640 inheritance_status status = zend_is_intersection_subtype_of_class(
641 fe_scope, fe_type, proto_scope, proto_class_name, proto_ce);
642 if (status == early_exit_status) {
643 return status;
644 }
645 if (status == INHERITANCE_UNRESOLVED) {
646 have_unresolved = true;
647 }
648 } ZEND_TYPE_FOREACH_END();
649 } else {
650 /* U_1|...|U_n < V_1|...|V_m if forall U_i. exists V_j. U_i < V_j.
651 * U_1|...|U_n < V_1&...&V_m if forall U_i. forall V_j. U_i < V_j.
652 * We need to iterate over fe_type (U_i) first and the logic is independent of
653 * whether proto_type is a union or intersection (only the inner check differs). */
654 early_exit_status = INHERITANCE_ERROR;
655 ZEND_TYPE_FOREACH(fe_type, single_type) {
656 zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
657 if (!fe_class_name) {
658 continue;
659 }
660
661 inheritance_status status = zend_is_class_subtype_of_type(
662 fe_scope, fe_class_name, proto_scope, proto_type);
663 if (status == early_exit_status) {
664 return status;
665 }
666 if (status == INHERITANCE_UNRESOLVED) {
667 have_unresolved = true;
668 }
669 } ZEND_TYPE_FOREACH_END();
670 }
671
672 if (!have_unresolved) {
673 return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
674 }
675
676 register_unresolved_classes(fe_scope, fe_type);
677 register_unresolved_classes(proto_scope, proto_type);
678 return INHERITANCE_UNRESOLVED;
679 }
680
zend_do_perform_arg_type_hint_check(zend_class_entry * fe_scope,zend_arg_info * fe_arg_info,zend_class_entry * proto_scope,zend_arg_info * proto_arg_info)681 static inheritance_status zend_do_perform_arg_type_hint_check(
682 zend_class_entry *fe_scope, zend_arg_info *fe_arg_info,
683 zend_class_entry *proto_scope, zend_arg_info *proto_arg_info) /* {{{ */
684 {
685 if (!ZEND_TYPE_IS_SET(fe_arg_info->type) || ZEND_TYPE_PURE_MASK(fe_arg_info->type) == MAY_BE_ANY) {
686 /* Child with no type or mixed type is always compatible */
687 return INHERITANCE_SUCCESS;
688 }
689
690 if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
691 /* Child defines a type, but parent doesn't, violates LSP */
692 return INHERITANCE_ERROR;
693 }
694
695 /* Contravariant type check is performed as a covariant type check with swapped
696 * argument order. */
697 return zend_perform_covariant_type_check(
698 proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
699 }
700 /* }}} */
701
702 /* For trait methods, fe_scope/proto_scope may differ from fe/proto->common.scope,
703 * as self will refer to the self of the class the trait is used in, not the trait
704 * the method was declared in. */
zend_do_perform_implementation_check(const zend_function * fe,zend_class_entry * fe_scope,const zend_function * proto,zend_class_entry * proto_scope)705 static inheritance_status zend_do_perform_implementation_check(
706 const zend_function *fe, zend_class_entry *fe_scope,
707 const zend_function *proto, zend_class_entry *proto_scope) /* {{{ */
708 {
709 uint32_t i, num_args, proto_num_args, fe_num_args;
710 inheritance_status status, local_status;
711 bool proto_is_variadic, fe_is_variadic;
712
713 /* Checks for constructors only if they are declared in an interface,
714 * or explicitly marked as abstract
715 */
716 ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
717 && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
718 && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)));
719
720 /* If the prototype method is private and not abstract, we do not enforce a signature.
721 * private abstract methods can only occur in traits. */
722 ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
723 || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
724
725 /* The number of required arguments cannot increase. */
726 if (proto->common.required_num_args < fe->common.required_num_args) {
727 return INHERITANCE_ERROR;
728 }
729
730 /* by-ref constraints on return values are covariant */
731 if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
732 && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
733 return INHERITANCE_ERROR;
734 }
735
736 proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
737 fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
738
739 /* A variadic function cannot become non-variadic */
740 if (proto_is_variadic && !fe_is_variadic) {
741 return INHERITANCE_ERROR;
742 }
743
744 /* The variadic argument is not included in the stored argument count. */
745 proto_num_args = proto->common.num_args + proto_is_variadic;
746 fe_num_args = fe->common.num_args + fe_is_variadic;
747 num_args = MAX(proto_num_args, fe_num_args);
748
749 status = INHERITANCE_SUCCESS;
750 for (i = 0; i < num_args; i++) {
751 zend_arg_info *proto_arg_info =
752 i < proto_num_args ? &proto->common.arg_info[i] :
753 proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
754 zend_arg_info *fe_arg_info =
755 i < fe_num_args ? &fe->common.arg_info[i] :
756 fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
757 if (!proto_arg_info) {
758 /* A new (optional) argument has been added, which is fine. */
759 continue;
760 }
761 if (!fe_arg_info) {
762 /* An argument has been removed. This is considered illegal, because arity checks
763 * work based on a model where passing more than the declared number of parameters
764 * to a function is an error. */
765 return INHERITANCE_ERROR;
766 }
767
768 local_status = zend_do_perform_arg_type_hint_check(
769 fe_scope, fe_arg_info, proto_scope, proto_arg_info);
770
771 if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
772 if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
773 return INHERITANCE_ERROR;
774 }
775 ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
776 status = INHERITANCE_UNRESOLVED;
777 }
778
779 /* by-ref constraints on arguments are invariant */
780 if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
781 return INHERITANCE_ERROR;
782 }
783 }
784
785 /* Check return type compatibility, but only if the prototype already specifies
786 * a return type. Adding a new return type is always valid. */
787 if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
788 /* Removing a return type is not valid, unless the parent return type is tentative. */
789 if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
790 if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
791 return INHERITANCE_ERROR;
792 }
793 if (status == INHERITANCE_SUCCESS) {
794 return INHERITANCE_WARNING;
795 }
796 return status;
797 }
798
799 local_status = zend_perform_covariant_type_check(
800 fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
801
802 if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
803 if (local_status == INHERITANCE_ERROR
804 && ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
805 local_status = INHERITANCE_WARNING;
806 }
807 return local_status;
808 }
809 }
810
811 return status;
812 }
813 /* }}} */
814
zend_append_type_hint(smart_str * str,zend_class_entry * scope,zend_arg_info * arg_info,bool return_hint)815 static ZEND_COLD void zend_append_type_hint(
816 smart_str *str, zend_class_entry *scope, zend_arg_info *arg_info, bool return_hint) /* {{{ */
817 {
818 if (ZEND_TYPE_IS_SET(arg_info->type)) {
819 zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
820 smart_str_append(str, type_str);
821 zend_string_release(type_str);
822 if (!return_hint) {
823 smart_str_appendc(str, ' ');
824 }
825 }
826 }
827 /* }}} */
828
zend_get_function_declaration(const zend_function * fptr,zend_class_entry * scope)829 static ZEND_COLD zend_string *zend_get_function_declaration(
830 const zend_function *fptr, zend_class_entry *scope) /* {{{ */
831 {
832 smart_str str = {0};
833
834 if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
835 smart_str_appends(&str, "& ");
836 }
837
838 if (fptr->common.scope) {
839 if (fptr->common.scope->ce_flags & ZEND_ACC_ANON_CLASS) {
840 /* cut off on NULL byte ... class@anonymous */
841 smart_str_appends(&str, ZSTR_VAL(fptr->common.scope->name));
842 } else {
843 smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), ZSTR_LEN(fptr->common.scope->name));
844 }
845 smart_str_appends(&str, "::");
846 }
847
848 smart_str_append(&str, fptr->common.function_name);
849 smart_str_appendc(&str, '(');
850
851 if (fptr->common.arg_info) {
852 uint32_t i, num_args, required;
853 zend_arg_info *arg_info = fptr->common.arg_info;
854
855 required = fptr->common.required_num_args;
856 num_args = fptr->common.num_args;
857 if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
858 num_args++;
859 }
860 for (i = 0; i < num_args;) {
861 zend_append_type_hint(&str, scope, arg_info, 0);
862
863 if (ZEND_ARG_SEND_MODE(arg_info)) {
864 smart_str_appendc(&str, '&');
865 }
866
867 if (ZEND_ARG_IS_VARIADIC(arg_info)) {
868 smart_str_appends(&str, "...");
869 }
870
871 smart_str_appendc(&str, '$');
872 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
873 smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
874 } else {
875 smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name));
876 }
877
878 if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
879 smart_str_appends(&str, " = ");
880
881 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
882 if (((zend_internal_arg_info*)arg_info)->default_value) {
883 smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->default_value);
884 } else {
885 smart_str_appends(&str, "<default>");
886 }
887 } else {
888 zend_op *precv = NULL;
889 {
890 uint32_t idx = i;
891 zend_op *op = fptr->op_array.opcodes;
892 zend_op *end = op + fptr->op_array.last;
893
894 ++idx;
895 while (op < end) {
896 if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
897 && op->op1.num == (zend_ulong)idx)
898 {
899 precv = op;
900 }
901 ++op;
902 }
903 }
904 if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
905 zval *zv = RT_CONSTANT(precv, precv->op2);
906
907 if (Z_TYPE_P(zv) == IS_FALSE) {
908 smart_str_appends(&str, "false");
909 } else if (Z_TYPE_P(zv) == IS_TRUE) {
910 smart_str_appends(&str, "true");
911 } else if (Z_TYPE_P(zv) == IS_NULL) {
912 smart_str_appends(&str, "null");
913 } else if (Z_TYPE_P(zv) == IS_STRING) {
914 smart_str_appendc(&str, '\'');
915 smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
916 if (Z_STRLEN_P(zv) > 10) {
917 smart_str_appends(&str, "...");
918 }
919 smart_str_appendc(&str, '\'');
920 } else if (Z_TYPE_P(zv) == IS_ARRAY) {
921 if (zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0) {
922 smart_str_appends(&str, "[]");
923 } else {
924 smart_str_appends(&str, "[...]");
925 }
926 } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
927 zend_ast *ast = Z_ASTVAL_P(zv);
928 if (ast->kind == ZEND_AST_CONSTANT) {
929 smart_str_append(&str, zend_ast_get_constant_name(ast));
930 } else if (ast->kind == ZEND_AST_CLASS_CONST) {
931 smart_str_append(&str, zend_ast_get_str(ast->child[0]));
932 smart_str_appends(&str, "::");
933 smart_str_append(&str, zend_ast_get_str(ast->child[1]));
934 } else {
935 smart_str_appends(&str, "<expression>");
936 }
937 } else {
938 zend_string *tmp_zv_str;
939 zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str);
940 smart_str_append(&str, zv_str);
941 zend_tmp_string_release(tmp_zv_str);
942 }
943 }
944 }
945 }
946
947 if (++i < num_args) {
948 smart_str_appends(&str, ", ");
949 }
950 arg_info++;
951 }
952 }
953
954 smart_str_appendc(&str, ')');
955
956 if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
957 smart_str_appends(&str, ": ");
958 zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, 1);
959 }
960 smart_str_0(&str);
961
962 return str.s;
963 }
964 /* }}} */
965
func_filename(const zend_function * fn)966 static zend_always_inline zend_string *func_filename(const zend_function *fn) {
967 return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
968 }
969
func_lineno(const zend_function * fn)970 static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
971 return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
972 }
973
emit_incompatible_method_error(const zend_function * child,zend_class_entry * child_scope,const zend_function * parent,zend_class_entry * parent_scope,inheritance_status status)974 static void ZEND_COLD emit_incompatible_method_error(
975 const zend_function *child, zend_class_entry *child_scope,
976 const zend_function *parent, zend_class_entry *parent_scope,
977 inheritance_status status) {
978 zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
979 zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
980 if (status == INHERITANCE_UNRESOLVED) {
981 /* Fetch the first unresolved class from registered autoloads */
982 zend_string *unresolved_class = NULL;
983 ZEND_HASH_FOREACH_STR_KEY(CG(delayed_autoloads), unresolved_class) {
984 break;
985 } ZEND_HASH_FOREACH_END();
986 ZEND_ASSERT(unresolved_class);
987
988 zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
989 "Could not check compatibility between %s and %s, because class %s is not available",
990 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
991 } else if (status == INHERITANCE_WARNING) {
992 zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
993 child->common.attributes,
994 "returntypewillchange",
995 sizeof("returntypewillchange")-1
996 );
997
998 if (!return_type_will_change_attribute) {
999 zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1000 "Return type of %s should either be compatible with %s, "
1001 "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1002 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1003 if (EG(exception)) {
1004 zend_exception_uncaught_error(
1005 "During inheritance of %s", ZSTR_VAL(parent_scope->name));
1006 }
1007 }
1008 } else {
1009 zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1010 "Declaration of %s must be compatible with %s",
1011 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1012 }
1013 zend_string_efree(child_prototype);
1014 zend_string_efree(parent_prototype);
1015 }
1016
perform_delayable_implementation_check(zend_class_entry * ce,const zend_function * fe,zend_class_entry * fe_scope,const zend_function * proto,zend_class_entry * proto_scope)1017 static void perform_delayable_implementation_check(
1018 zend_class_entry *ce,
1019 const zend_function *fe, zend_class_entry *fe_scope,
1020 const zend_function *proto, zend_class_entry *proto_scope)
1021 {
1022 inheritance_status status =
1023 zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1024 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
1025 if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
1026 add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1027 } else {
1028 ZEND_ASSERT(status == INHERITANCE_ERROR || status == INHERITANCE_WARNING);
1029 emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1030 }
1031 }
1032 }
1033
do_inheritance_check_on_method_ex(zend_function * child,zend_class_entry * child_scope,zend_function * parent,zend_class_entry * parent_scope,zend_class_entry * ce,zval * child_zv,bool check_visibility,bool check_only,bool checked)1034 static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
1035 zend_function *child, zend_class_entry *child_scope,
1036 zend_function *parent, zend_class_entry *parent_scope,
1037 zend_class_entry *ce, zval *child_zv,
1038 bool check_visibility, bool check_only, bool checked) /* {{{ */
1039 {
1040 uint32_t child_flags;
1041 uint32_t parent_flags = parent->common.fn_flags;
1042 zend_function *proto;
1043
1044 if (UNEXPECTED((parent_flags & ZEND_ACC_PRIVATE) && !(parent_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_CTOR))) {
1045 if (!check_only) {
1046 child->common.fn_flags |= ZEND_ACC_CHANGED;
1047 }
1048 /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
1049 return INHERITANCE_SUCCESS;
1050 }
1051
1052 if (!checked && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
1053 if (check_only) {
1054 return INHERITANCE_ERROR;
1055 }
1056 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1057 "Cannot override final method %s::%s()",
1058 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
1059 }
1060
1061 child_flags = child->common.fn_flags;
1062 /* You cannot change from static to non static and vice versa.
1063 */
1064 if (!checked && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
1065 if (check_only) {
1066 return INHERITANCE_ERROR;
1067 }
1068 if (child_flags & ZEND_ACC_STATIC) {
1069 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1070 "Cannot make non static method %s::%s() static in class %s",
1071 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1072 } else {
1073 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1074 "Cannot make static method %s::%s() non static in class %s",
1075 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1076 }
1077 }
1078
1079 /* Disallow making an inherited method abstract. */
1080 if (!checked && UNEXPECTED((child_flags & ZEND_ACC_ABSTRACT) > (parent_flags & ZEND_ACC_ABSTRACT))) {
1081 if (check_only) {
1082 return INHERITANCE_ERROR;
1083 }
1084 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1085 "Cannot make non abstract method %s::%s() abstract in class %s",
1086 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1087 }
1088
1089 if (!check_only && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
1090 child->common.fn_flags |= ZEND_ACC_CHANGED;
1091 }
1092
1093 proto = parent->common.prototype ?
1094 parent->common.prototype : parent;
1095
1096 if (parent_flags & ZEND_ACC_CTOR) {
1097 /* ctors only have a prototype if is abstract (or comes from an interface) */
1098 /* and if that is the case, we want to check inheritance against it */
1099 if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1100 return INHERITANCE_SUCCESS;
1101 }
1102 parent = proto;
1103 }
1104
1105 if (!check_only && child->common.prototype != proto && child_zv) {
1106 do {
1107 if (child->common.scope != ce && child->type == ZEND_USER_FUNCTION) {
1108 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
1109 /* Few parent interfaces contain the same method */
1110 break;
1111 } else {
1112 /* op_array wasn't duplicated yet */
1113 zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1114 memcpy(new_function, child, sizeof(zend_op_array));
1115 Z_PTR_P(child_zv) = child = new_function;
1116 }
1117 }
1118 child->common.prototype = proto;
1119 } while (0);
1120 }
1121
1122 /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1123 if (!checked && check_visibility
1124 && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1125 if (check_only) {
1126 return INHERITANCE_ERROR;
1127 }
1128 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1129 "Access level to %s::%s() must be %s (as in class %s)%s",
1130 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");
1131 }
1132
1133 if (!checked) {
1134 if (check_only) {
1135 return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1136 }
1137 perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1138 }
1139 return INHERITANCE_SUCCESS;
1140 }
1141 /* }}} */
1142
do_inheritance_check_on_method(zend_function * child,zend_class_entry * child_scope,zend_function * parent,zend_class_entry * parent_scope,zend_class_entry * ce,zval * child_zv,bool check_visibility)1143 static zend_never_inline void do_inheritance_check_on_method(
1144 zend_function *child, zend_class_entry *child_scope,
1145 zend_function *parent, zend_class_entry *parent_scope,
1146 zend_class_entry *ce, zval *child_zv, bool check_visibility)
1147 {
1148 do_inheritance_check_on_method_ex(child, child_scope, parent, parent_scope, ce, child_zv, check_visibility, 0, 0);
1149 }
1150
do_inherit_method(zend_string * key,zend_function * parent,zend_class_entry * ce,bool is_interface,bool checked)1151 static zend_always_inline void do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce, bool is_interface, bool checked) /* {{{ */
1152 {
1153 zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1154
1155 if (child) {
1156 zend_function *func = (zend_function*)Z_PTR_P(child);
1157
1158 if (is_interface && UNEXPECTED(func == parent)) {
1159 /* The same method in interface may be inherited few times */
1160 return;
1161 }
1162
1163 if (checked) {
1164 do_inheritance_check_on_method_ex(
1165 func, func->common.scope, parent, parent->common.scope, ce, child,
1166 /* check_visibility */ 1, 0, checked);
1167 } else {
1168 do_inheritance_check_on_method(
1169 func, func->common.scope, parent, parent->common.scope, ce, child,
1170 /* check_visibility */ 1);
1171 }
1172 } else {
1173
1174 if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1175 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1176 }
1177
1178 parent = zend_duplicate_function(parent, ce);
1179
1180 if (!is_interface) {
1181 _zend_hash_append_ptr(&ce->function_table, key, parent);
1182 } else {
1183 zend_hash_add_new_ptr(&ce->function_table, key, parent);
1184 }
1185 }
1186 }
1187 /* }}} */
1188
property_types_compatible(const zend_property_info * parent_info,const zend_property_info * child_info)1189 inheritance_status property_types_compatible(
1190 const zend_property_info *parent_info, const zend_property_info *child_info) {
1191 if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
1192 && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1193 return INHERITANCE_SUCCESS;
1194 }
1195
1196 if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1197 return INHERITANCE_ERROR;
1198 }
1199
1200 /* Perform a covariant type check in both directions to determined invariance. */
1201 inheritance_status status1 = zend_perform_covariant_type_check(
1202 child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1203 inheritance_status status2 = zend_perform_covariant_type_check(
1204 parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1205 if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1206 return INHERITANCE_SUCCESS;
1207 }
1208 if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1209 return INHERITANCE_ERROR;
1210 }
1211 ZEND_ASSERT(status1 == INHERITANCE_UNRESOLVED || status2 == INHERITANCE_UNRESOLVED);
1212 return INHERITANCE_UNRESOLVED;
1213 }
1214
emit_incompatible_property_error(const zend_property_info * child,const zend_property_info * parent)1215 static void emit_incompatible_property_error(
1216 const zend_property_info *child, const zend_property_info *parent) {
1217 zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1218 zend_error_noreturn(E_COMPILE_ERROR,
1219 "Type of %s::$%s must be %s (as in class %s)",
1220 ZSTR_VAL(child->ce->name),
1221 zend_get_unmangled_property_name(child->name),
1222 ZSTR_VAL(type_str),
1223 ZSTR_VAL(parent->ce->name));
1224 }
1225
do_inherit_property(zend_property_info * parent_info,zend_string * key,zend_class_entry * ce)1226 static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1227 {
1228 zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1229 zend_property_info *child_info;
1230
1231 if (UNEXPECTED(child)) {
1232 child_info = Z_PTR_P(child);
1233 if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1234 child_info->flags |= ZEND_ACC_CHANGED;
1235 }
1236 if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1237 if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
1238 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1239 (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1240 (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
1241 }
1242 if (UNEXPECTED((child_info->flags & ZEND_ACC_READONLY) != (parent_info->flags & ZEND_ACC_READONLY))) {
1243 zend_error_noreturn(E_COMPILE_ERROR,
1244 "Cannot redeclare %s property %s::$%s as %s %s::$%s",
1245 parent_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1246 ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1247 child_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1248 ZSTR_VAL(ce->name), ZSTR_VAL(key));
1249 }
1250
1251 if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1252 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");
1253 } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
1254 int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
1255 int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1256
1257 /* Don't keep default properties in GC (they may be freed by opcache) */
1258 zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1259 ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1260 ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1261 child_info->offset = parent_info->offset;
1262 }
1263
1264 if (UNEXPECTED(ZEND_TYPE_IS_SET(parent_info->type))) {
1265 inheritance_status status = property_types_compatible(parent_info, child_info);
1266 if (status == INHERITANCE_ERROR) {
1267 emit_incompatible_property_error(child_info, parent_info);
1268 }
1269 if (status == INHERITANCE_UNRESOLVED) {
1270 add_property_compatibility_obligation(ce, child_info, parent_info);
1271 }
1272 } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1273 zend_error_noreturn(E_COMPILE_ERROR,
1274 "Type of %s::$%s must not be defined (as in class %s)",
1275 ZSTR_VAL(ce->name),
1276 ZSTR_VAL(key),
1277 ZSTR_VAL(parent_info->ce->name));
1278 }
1279 }
1280 } else {
1281 _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1282 }
1283 }
1284 /* }}} */
1285
do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1286 static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1287 {
1288 if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
1289 zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1290 }
1291 /* This should be prevented by the class lookup logic. */
1292 ZEND_ASSERT(ce != iface);
1293 }
1294 /* }}} */
1295
zend_do_inherit_interfaces(zend_class_entry * ce,const zend_class_entry * iface)1296 static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1297 {
1298 /* expects interface to be contained in ce's interface list already */
1299 uint32_t i, ce_num, if_num = iface->num_interfaces;
1300 zend_class_entry *entry;
1301
1302 ce_num = ce->num_interfaces;
1303
1304 if (ce->type == ZEND_INTERNAL_CLASS) {
1305 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1306 } else {
1307 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1308 }
1309
1310 /* Inherit the interfaces, only if they're not already inherited by the class */
1311 while (if_num--) {
1312 entry = iface->interfaces[if_num];
1313 for (i = 0; i < ce_num; i++) {
1314 if (ce->interfaces[i] == entry) {
1315 break;
1316 }
1317 }
1318 if (i == ce_num) {
1319 ce->interfaces[ce->num_interfaces++] = entry;
1320 }
1321 }
1322 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1323
1324 /* and now call the implementing handlers */
1325 while (ce_num < ce->num_interfaces) {
1326 do_implement_interface(ce, ce->interfaces[ce_num++]);
1327 }
1328 }
1329 /* }}} */
1330
do_inherit_class_constant(zend_string * name,zend_class_constant * parent_const,zend_class_entry * ce)1331 static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
1332 {
1333 zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1334 zend_class_constant *c;
1335
1336 if (zv != NULL) {
1337 c = (zend_class_constant*)Z_PTR_P(zv);
1338 if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PPP_MASK))) {
1339 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s",
1340 ZSTR_VAL(ce->name), ZSTR_VAL(name), zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_const)), ZSTR_VAL(parent_const->ce->name), (ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PUBLIC) ? "" : " or weaker");
1341 }
1342
1343 if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_FINAL))) {
1344 zend_error_noreturn(
1345 E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1346 ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(parent_const->ce->name), ZSTR_VAL(name)
1347 );
1348 }
1349 } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1350 if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1351 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1352 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1353 if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
1354 c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1355 memcpy(c, parent_const, sizeof(zend_class_constant));
1356 parent_const = c;
1357 Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1358 }
1359 }
1360 if (ce->type & ZEND_INTERNAL_CLASS) {
1361 c = pemalloc(sizeof(zend_class_constant), 1);
1362 memcpy(c, parent_const, sizeof(zend_class_constant));
1363 parent_const = c;
1364 }
1365 _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1366 }
1367 }
1368 /* }}} */
1369
zend_build_properties_info_table(zend_class_entry * ce)1370 void zend_build_properties_info_table(zend_class_entry *ce)
1371 {
1372 zend_property_info **table, *prop;
1373 size_t size;
1374 if (ce->default_properties_count == 0) {
1375 return;
1376 }
1377
1378 ZEND_ASSERT(ce->properties_info_table == NULL);
1379 size = sizeof(zend_property_info *) * ce->default_properties_count;
1380 if (ce->type == ZEND_USER_CLASS) {
1381 ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1382 } else {
1383 ce->properties_info_table = table = pemalloc(size, 1);
1384 }
1385
1386 /* Dead slots may be left behind during inheritance. Make sure these are NULLed out. */
1387 memset(table, 0, size);
1388
1389 if (ce->parent && ce->parent->default_properties_count != 0) {
1390 zend_property_info **parent_table = ce->parent->properties_info_table;
1391 memcpy(
1392 table, parent_table,
1393 sizeof(zend_property_info *) * ce->parent->default_properties_count
1394 );
1395
1396 /* Child did not add any new properties, we are done */
1397 if (ce->default_properties_count == ce->parent->default_properties_count) {
1398 return;
1399 }
1400 }
1401
1402 ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
1403 if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0) {
1404 table[OBJ_PROP_TO_NUM(prop->offset)] = prop;
1405 }
1406 } ZEND_HASH_FOREACH_END();
1407 }
1408
zend_do_inheritance_ex(zend_class_entry * ce,zend_class_entry * parent_ce,bool checked)1409 ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked) /* {{{ */
1410 {
1411 zend_property_info *property_info;
1412 zend_function *func;
1413 zend_string *key;
1414
1415 if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) {
1416 /* Interface can only inherit other interfaces */
1417 if (UNEXPECTED(!(parent_ce->ce_flags & ZEND_ACC_INTERFACE))) {
1418 zend_error_noreturn(E_COMPILE_ERROR, "Interface %s cannot extend class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1419 }
1420 } else if (UNEXPECTED(parent_ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_FINAL))) {
1421 /* Class must not extend a final class */
1422 if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1423 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1424 }
1425
1426 /* Class declaration must not extend traits or interfaces */
1427 if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1428 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1429 ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1430 );
1431 }
1432 }
1433
1434 if (ce->parent_name) {
1435 zend_string_release_ex(ce->parent_name, 0);
1436 }
1437 ce->parent = parent_ce;
1438 ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1439
1440 /* Inherit properties */
1441 if (parent_ce->default_properties_count) {
1442 zval *src, *dst, *end;
1443
1444 if (ce->default_properties_count) {
1445 zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1446 src = ce->default_properties_table + ce->default_properties_count;
1447 end = table + parent_ce->default_properties_count;
1448 dst = end + ce->default_properties_count;
1449 ce->default_properties_table = table;
1450 do {
1451 dst--;
1452 src--;
1453 ZVAL_COPY_VALUE_PROP(dst, src);
1454 } while (dst != end);
1455 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1456 end = ce->default_properties_table;
1457 } else {
1458 end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1459 dst = end + parent_ce->default_properties_count;
1460 ce->default_properties_table = end;
1461 }
1462 src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1463 if (UNEXPECTED(parent_ce->type != ce->type)) {
1464 /* User class extends internal */
1465 do {
1466 dst--;
1467 src--;
1468 ZVAL_COPY_OR_DUP_PROP(dst, src);
1469 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1470 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1471 ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1472 }
1473 continue;
1474 } while (dst != end);
1475 } else {
1476 do {
1477 dst--;
1478 src--;
1479 ZVAL_COPY_PROP(dst, src);
1480 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1481 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1482 ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1483 }
1484 continue;
1485 } while (dst != end);
1486 }
1487 ce->default_properties_count += parent_ce->default_properties_count;
1488 }
1489
1490 if (parent_ce->default_static_members_count) {
1491 zval *src, *dst, *end;
1492
1493 if (ce->default_static_members_count) {
1494 zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1495 src = ce->default_static_members_table + ce->default_static_members_count;
1496 end = table + parent_ce->default_static_members_count;
1497 dst = end + ce->default_static_members_count;
1498 ce->default_static_members_table = table;
1499 do {
1500 dst--;
1501 src--;
1502 ZVAL_COPY_VALUE(dst, src);
1503 } while (dst != end);
1504 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1505 end = ce->default_static_members_table;
1506 } else {
1507 end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1508 dst = end + parent_ce->default_static_members_count;
1509 ce->default_static_members_table = end;
1510 }
1511 src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1512 do {
1513 dst--;
1514 src--;
1515 if (Z_TYPE_P(src) == IS_INDIRECT) {
1516 ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1517 } else {
1518 ZVAL_INDIRECT(dst, src);
1519 }
1520 if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1521 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1522 ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
1523 }
1524 } while (dst != end);
1525 ce->default_static_members_count += parent_ce->default_static_members_count;
1526 if (!ZEND_MAP_PTR(ce->static_members_table)) {
1527 if (ce->type == ZEND_INTERNAL_CLASS &&
1528 ce->info.internal.module->type == MODULE_PERSISTENT) {
1529 ZEND_MAP_PTR_NEW(ce->static_members_table);
1530 } else {
1531 ZEND_MAP_PTR_INIT(ce->static_members_table,
1532 zend_arena_alloc(&CG(arena), sizeof(zval *)));
1533 ZEND_MAP_PTR_SET(ce->static_members_table, NULL);
1534 }
1535 }
1536 }
1537
1538 ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
1539 if (property_info->ce == ce) {
1540 if (property_info->flags & ZEND_ACC_STATIC) {
1541 property_info->offset += parent_ce->default_static_members_count;
1542 } else {
1543 property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1544 }
1545 }
1546 } ZEND_HASH_FOREACH_END();
1547
1548 if (zend_hash_num_elements(&parent_ce->properties_info)) {
1549 zend_hash_extend(&ce->properties_info,
1550 zend_hash_num_elements(&ce->properties_info) +
1551 zend_hash_num_elements(&parent_ce->properties_info), 0);
1552
1553 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1554 do_inherit_property(property_info, key, ce);
1555 } ZEND_HASH_FOREACH_END();
1556 }
1557
1558 if (zend_hash_num_elements(&parent_ce->constants_table)) {
1559 zend_class_constant *c;
1560
1561 zend_hash_extend(&ce->constants_table,
1562 zend_hash_num_elements(&ce->constants_table) +
1563 zend_hash_num_elements(&parent_ce->constants_table), 0);
1564
1565 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
1566 do_inherit_class_constant(key, c, ce);
1567 } ZEND_HASH_FOREACH_END();
1568 }
1569
1570 if (zend_hash_num_elements(&parent_ce->function_table)) {
1571 zend_hash_extend(&ce->function_table,
1572 zend_hash_num_elements(&ce->function_table) +
1573 zend_hash_num_elements(&parent_ce->function_table), 0);
1574
1575 if (checked) {
1576 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1577 do_inherit_method(key, func, ce, 0, 1);
1578 } ZEND_HASH_FOREACH_END();
1579 } else {
1580 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1581 do_inherit_method(key, func, ce, 0, 0);
1582 } ZEND_HASH_FOREACH_END();
1583 }
1584 }
1585
1586 do_inherit_parent_constructor(ce);
1587
1588 if (ce->type == ZEND_INTERNAL_CLASS) {
1589 if (parent_ce->num_interfaces) {
1590 zend_do_inherit_interfaces(ce, parent_ce);
1591 }
1592
1593 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1594 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1595 }
1596 }
1597 ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_USE_GUARDS | ZEND_ACC_NOT_SERIALIZABLE);
1598 }
1599 /* }}} */
1600
do_inherit_constant_check(zend_class_entry * ce,zend_class_constant * parent_constant,zend_string * name)1601 static bool do_inherit_constant_check(
1602 zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name
1603 ) {
1604 zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1605 if (zv == NULL) {
1606 return true;
1607 }
1608
1609 zend_class_constant *old_constant = Z_PTR_P(zv);
1610 if (parent_constant->ce != old_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
1611 zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1612 ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1613 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
1614 );
1615 }
1616
1617 if (old_constant->ce != parent_constant->ce && old_constant->ce != ce) {
1618 zend_error_noreturn(E_COMPILE_ERROR,
1619 "Class %s inherits both %s::%s and %s::%s, which is ambiguous",
1620 ZSTR_VAL(ce->name),
1621 ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
1622 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
1623 }
1624
1625 return false;
1626 }
1627 /* }}} */
1628
do_inherit_iface_constant(zend_string * name,zend_class_constant * c,zend_class_entry * ce,zend_class_entry * iface)1629 static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1630 {
1631 if (do_inherit_constant_check(ce, c, name)) {
1632 zend_class_constant *ct;
1633 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
1634 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1635 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1636 if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
1637 ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1638 memcpy(ct, c, sizeof(zend_class_constant));
1639 c = ct;
1640 Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1641 }
1642 }
1643 if (ce->type & ZEND_INTERNAL_CLASS) {
1644 ct = pemalloc(sizeof(zend_class_constant), 1);
1645 memcpy(ct, c, sizeof(zend_class_constant));
1646 c = ct;
1647 }
1648 zend_hash_update_ptr(&ce->constants_table, name, c);
1649 }
1650 }
1651 /* }}} */
1652
do_interface_implementation(zend_class_entry * ce,zend_class_entry * iface)1653 static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1654 {
1655 zend_function *func;
1656 zend_string *key;
1657 zend_class_constant *c;
1658
1659 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1660 do_inherit_iface_constant(key, c, ce, iface);
1661 } ZEND_HASH_FOREACH_END();
1662
1663 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
1664 do_inherit_method(key, func, ce, 1, 0);
1665 } ZEND_HASH_FOREACH_END();
1666
1667 do_implement_interface(ce, iface);
1668 if (iface->num_interfaces) {
1669 zend_do_inherit_interfaces(ce, iface);
1670 }
1671 }
1672 /* }}} */
1673
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1674 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1675 {
1676 uint32_t i, ignore = 0;
1677 uint32_t current_iface_num = ce->num_interfaces;
1678 uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
1679 zend_string *key;
1680 zend_class_constant *c;
1681
1682 ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
1683
1684 for (i = 0; i < ce->num_interfaces; i++) {
1685 if (ce->interfaces[i] == NULL) {
1686 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
1687 i--;
1688 } else if (ce->interfaces[i] == iface) {
1689 if (EXPECTED(i < parent_iface_num)) {
1690 ignore = 1;
1691 } else {
1692 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1693 }
1694 }
1695 }
1696 if (ignore) {
1697 /* Check for attempt to redeclare interface constants */
1698 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1699 do_inherit_constant_check(ce, c, key);
1700 } ZEND_HASH_FOREACH_END();
1701 } else {
1702 if (ce->num_interfaces >= current_iface_num) {
1703 if (ce->type == ZEND_INTERNAL_CLASS) {
1704 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1705 } else {
1706 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1707 }
1708 }
1709 ce->interfaces[ce->num_interfaces++] = iface;
1710
1711 do_interface_implementation(ce, iface);
1712 }
1713 }
1714 /* }}} */
1715
zend_do_implement_interfaces(zend_class_entry * ce,zend_class_entry ** interfaces)1716 static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
1717 {
1718 zend_class_entry *iface;
1719 uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
1720 uint32_t num_interfaces = num_parent_interfaces;
1721 zend_string *key;
1722 zend_class_constant *c;
1723 uint32_t i, j;
1724
1725 for (i = 0; i < ce->num_interfaces; i++) {
1726 iface = interfaces[num_parent_interfaces + i];
1727 if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
1728 add_dependency_obligation(ce, iface);
1729 }
1730 if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
1731 efree(interfaces);
1732 zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1733 return;
1734 }
1735 for (j = 0; j < num_interfaces; j++) {
1736 if (interfaces[j] == iface) {
1737 if (j >= num_parent_interfaces) {
1738 efree(interfaces);
1739 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1740 return;
1741 }
1742 /* skip duplications */
1743 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1744 do_inherit_constant_check(ce, c, key);
1745 } ZEND_HASH_FOREACH_END();
1746
1747 iface = NULL;
1748 break;
1749 }
1750 }
1751 if (iface) {
1752 interfaces[num_interfaces] = iface;
1753 num_interfaces++;
1754 }
1755 }
1756
1757 if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
1758 for (i = 0; i < ce->num_interfaces; i++) {
1759 zend_string_release_ex(ce->interface_names[i].name, 0);
1760 zend_string_release_ex(ce->interface_names[i].lc_name, 0);
1761 }
1762 efree(ce->interface_names);
1763 }
1764
1765 ce->num_interfaces = num_interfaces;
1766 ce->interfaces = interfaces;
1767 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1768
1769 for (i = 0; i < num_parent_interfaces; i++) {
1770 do_implement_interface(ce, ce->interfaces[i]);
1771 }
1772 /* Note that new interfaces can be added during this loop due to interface inheritance.
1773 * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */
1774 for (; i < num_interfaces; i++) {
1775 do_interface_implementation(ce, ce->interfaces[i]);
1776 }
1777 }
1778 /* }}} */
1779
fixup_trait_scope(const zend_function * fn,zend_class_entry * ce)1780 static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
1781 {
1782 /* self in trait methods should be resolved to the using class, not the trait. */
1783 return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
1784 }
1785
zend_add_trait_method(zend_class_entry * ce,zend_string * name,zend_string * key,zend_function * fn)1786 static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
1787 {
1788 zend_function *existing_fn = NULL;
1789 zend_function *new_fn;
1790
1791 if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
1792 /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
1793 * of where it is coming from there is no conflict and we do not need to add it again */
1794 if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
1795 (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
1796 (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1797 return;
1798 }
1799
1800 /* Abstract method signatures from the trait must be satisfied. */
1801 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1802 /* "abstract private" methods in traits were not available prior to PHP 8.
1803 * As such, "abstract protected" was sometimes used to indicate trait requirements,
1804 * even though the "implementing" method was private. Do not check visibility
1805 * requirements to maintain backwards-compatibility with such usage.
1806 */
1807 do_inheritance_check_on_method(
1808 existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
1809 ce, NULL, /* check_visibility */ 0);
1810 return;
1811 }
1812
1813 if (existing_fn->common.scope == ce) {
1814 /* members from the current class override trait methods */
1815 return;
1816 } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
1817 && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
1818 /* two traits can't define the same non-abstract method */
1819 zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
1820 ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
1821 ZSTR_VAL(ce->name), ZSTR_VAL(name),
1822 ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
1823 } else {
1824 /* Inherited members are overridden by members inserted by traits.
1825 * Check whether the trait method fulfills the inheritance requirements. */
1826 do_inheritance_check_on_method(
1827 fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce),
1828 ce, NULL, /* check_visibility */ 1);
1829 }
1830 }
1831
1832 if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
1833 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
1834 memcpy(new_fn, fn, sizeof(zend_internal_function));
1835 new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
1836 } else {
1837 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1838 memcpy(new_fn, fn, sizeof(zend_op_array));
1839 new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE;
1840 new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
1841 }
1842
1843 /* Reassign method name, in case it is an alias. */
1844 new_fn->common.function_name = name;
1845 function_add_ref(new_fn);
1846 fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
1847 zend_add_magic_method(ce, fn, key);
1848 }
1849 /* }}} */
1850
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce)1851 static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
1852 {
1853 if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1854
1855 fn->common.scope = ce;
1856
1857 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1858 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1859 }
1860 if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
1861 ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
1862 }
1863 }
1864 }
1865 /* }}} */
1866
zend_traits_copy_functions(zend_string * fnname,zend_function * fn,zend_class_entry * ce,HashTable * exclude_table,zend_class_entry ** aliases)1867 static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
1868 {
1869 zend_trait_alias *alias, **alias_ptr;
1870 zend_string *lcname;
1871 zend_function fn_copy;
1872 int i;
1873
1874 /* apply aliases which are qualified with a class name, there should not be any ambiguity */
1875 if (ce->trait_aliases) {
1876 alias_ptr = ce->trait_aliases;
1877 alias = *alias_ptr;
1878 i = 0;
1879 while (alias) {
1880 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
1881 if (alias->alias != NULL
1882 && fn->common.scope == aliases[i]
1883 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
1884 ) {
1885 fn_copy = *fn;
1886
1887 /* if it is 0, no modifiers have been changed */
1888 if (alias->modifiers) {
1889 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
1890 }
1891
1892 lcname = zend_string_tolower(alias->alias);
1893 zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
1894 zend_string_release_ex(lcname, 0);
1895 }
1896 alias_ptr++;
1897 alias = *alias_ptr;
1898 i++;
1899 }
1900 }
1901
1902 if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
1903 /* is not in hashtable, thus, function is not to be excluded */
1904 memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
1905
1906 /* apply aliases which have not alias name, just setting visibility */
1907 if (ce->trait_aliases) {
1908 alias_ptr = ce->trait_aliases;
1909 alias = *alias_ptr;
1910 i = 0;
1911 while (alias) {
1912 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
1913 if (alias->alias == NULL && alias->modifiers != 0
1914 && fn->common.scope == aliases[i]
1915 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
1916 ) {
1917 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
1918 }
1919 alias_ptr++;
1920 alias = *alias_ptr;
1921 i++;
1922 }
1923 }
1924
1925 zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
1926 }
1927 }
1928 /* }}} */
1929
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait,zend_class_entry ** traits)1930 static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait, zend_class_entry **traits) /* {{{ */
1931 {
1932 uint32_t i;
1933
1934 if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
1935 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));
1936 return 0;
1937 }
1938
1939 for (i = 0; i < ce->num_traits; i++) {
1940 if (traits[i] == trait) {
1941 return i;
1942 }
1943 }
1944 zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
1945 return 0;
1946 }
1947 /* }}} */
1948
zend_traits_init_trait_structures(zend_class_entry * ce,zend_class_entry ** traits,HashTable *** exclude_tables_ptr,zend_class_entry *** aliases_ptr)1949 static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
1950 {
1951 size_t i, j = 0;
1952 zend_trait_precedence **precedences;
1953 zend_trait_precedence *cur_precedence;
1954 zend_trait_method_reference *cur_method_ref;
1955 zend_string *lc_trait_name;
1956 zend_string *lcname;
1957 HashTable **exclude_tables = NULL;
1958 zend_class_entry **aliases = NULL;
1959 zend_class_entry *trait;
1960
1961 /* resolve class references */
1962 if (ce->trait_precedences) {
1963 exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
1964 i = 0;
1965 precedences = ce->trait_precedences;
1966 ce->trait_precedences = NULL;
1967 while ((cur_precedence = precedences[i])) {
1968 /** Resolve classes for all precedence operations. */
1969 cur_method_ref = &cur_precedence->trait_method;
1970 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
1971 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
1972 zend_string_release_ex(lc_trait_name, 0);
1973 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
1974 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
1975 }
1976 zend_check_trait_usage(ce, trait, traits);
1977
1978 /** Ensure that the preferred method is actually available. */
1979 lcname = zend_string_tolower(cur_method_ref->method_name);
1980 if (!zend_hash_exists(&trait->function_table, lcname)) {
1981 zend_error_noreturn(E_COMPILE_ERROR,
1982 "A precedence rule was defined for %s::%s but this method does not exist",
1983 ZSTR_VAL(trait->name),
1984 ZSTR_VAL(cur_method_ref->method_name));
1985 }
1986
1987 /** With the other traits, we are more permissive.
1988 We do not give errors for those. This allows to be more
1989 defensive in such definitions.
1990 However, we want to make sure that the insteadof declaration
1991 is consistent in itself.
1992 */
1993
1994 for (j = 0; j < cur_precedence->num_excludes; j++) {
1995 zend_string* class_name = cur_precedence->exclude_class_names[j];
1996 zend_class_entry *exclude_ce;
1997 uint32_t trait_num;
1998
1999 lc_trait_name = zend_string_tolower(class_name);
2000 exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2001 zend_string_release_ex(lc_trait_name, 0);
2002 if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2003 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2004 }
2005 trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2006 if (!exclude_tables[trait_num]) {
2007 ALLOC_HASHTABLE(exclude_tables[trait_num]);
2008 zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2009 }
2010 if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2011 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));
2012 }
2013
2014 /* make sure that the trait method is not from a class mentioned in
2015 exclude_from_classes, for consistency */
2016 if (trait == exclude_ce) {
2017 zend_error_noreturn(E_COMPILE_ERROR,
2018 "Inconsistent insteadof definition. "
2019 "The method %s is to be used from %s, but %s is also on the exclude list",
2020 ZSTR_VAL(cur_method_ref->method_name),
2021 ZSTR_VAL(trait->name),
2022 ZSTR_VAL(trait->name));
2023 }
2024 }
2025 zend_string_release_ex(lcname, 0);
2026 i++;
2027 }
2028 ce->trait_precedences = precedences;
2029 }
2030
2031 if (ce->trait_aliases) {
2032 i = 0;
2033 while (ce->trait_aliases[i]) {
2034 i++;
2035 }
2036 aliases = ecalloc(i, sizeof(zend_class_entry*));
2037 i = 0;
2038 while (ce->trait_aliases[i]) {
2039 zend_trait_alias *cur_alias = ce->trait_aliases[i];
2040 cur_method_ref = &ce->trait_aliases[i]->trait_method;
2041 lcname = zend_string_tolower(cur_method_ref->method_name);
2042 if (cur_method_ref->class_name) {
2043 /* For all aliases with an explicit class name, resolve the class now. */
2044 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2045 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2046 zend_string_release_ex(lc_trait_name, 0);
2047 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2048 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2049 }
2050 zend_check_trait_usage(ce, trait, traits);
2051 aliases[i] = trait;
2052
2053 /* And, ensure that the referenced method is resolvable, too. */
2054 if (!zend_hash_exists(&trait->function_table, lcname)) {
2055 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));
2056 }
2057 } else {
2058 /* Find out which trait this method refers to. */
2059 trait = NULL;
2060 for (j = 0; j < ce->num_traits; j++) {
2061 if (traits[j]) {
2062 if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2063 if (!trait) {
2064 trait = traits[j];
2065 continue;
2066 }
2067
2068 zend_error_noreturn(E_COMPILE_ERROR,
2069 "An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
2070 ZSTR_VAL(cur_method_ref->method_name),
2071 ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2072 ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2073 ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2074 }
2075 }
2076 }
2077
2078 /* Non-absolute method reference refers to method that does not exist. */
2079 if (!trait) {
2080 if (cur_alias->alias) {
2081 zend_error_noreturn(E_COMPILE_ERROR,
2082 "An alias (%s) was defined for method %s(), but this method does not exist",
2083 ZSTR_VAL(cur_alias->alias),
2084 ZSTR_VAL(cur_alias->trait_method.method_name));
2085 } else {
2086 zend_error_noreturn(E_COMPILE_ERROR,
2087 "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2088 ZSTR_VAL(cur_alias->trait_method.method_name));
2089 }
2090 }
2091
2092 aliases[i] = trait;
2093 }
2094 zend_string_release_ex(lcname, 0);
2095 i++;
2096 }
2097 }
2098
2099 *exclude_tables_ptr = exclude_tables;
2100 *aliases_ptr = aliases;
2101 }
2102 /* }}} */
2103
zend_do_traits_method_binding(zend_class_entry * ce,zend_class_entry ** traits,HashTable ** exclude_tables,zend_class_entry ** aliases)2104 static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
2105 {
2106 uint32_t i;
2107 zend_string *key;
2108 zend_function *fn;
2109
2110 if (exclude_tables) {
2111 for (i = 0; i < ce->num_traits; i++) {
2112 if (traits[i]) {
2113 /* copies functions, applies defined aliasing, and excludes unused trait methods */
2114 ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2115 zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2116 } ZEND_HASH_FOREACH_END();
2117
2118 if (exclude_tables[i]) {
2119 zend_hash_destroy(exclude_tables[i]);
2120 FREE_HASHTABLE(exclude_tables[i]);
2121 exclude_tables[i] = NULL;
2122 }
2123 }
2124 }
2125 } else {
2126 for (i = 0; i < ce->num_traits; i++) {
2127 if (traits[i]) {
2128 ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2129 zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2130 } ZEND_HASH_FOREACH_END();
2131 }
2132 }
2133 }
2134
2135 ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
2136 zend_fixup_trait_method(fn, ce);
2137 } ZEND_HASH_FOREACH_END();
2138 }
2139 /* }}} */
2140
find_first_definition(zend_class_entry * ce,zend_class_entry ** traits,size_t current_trait,zend_string * prop_name,zend_class_entry * colliding_ce)2141 static zend_class_entry* find_first_definition(zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *prop_name, zend_class_entry *colliding_ce) /* {{{ */
2142 {
2143 size_t i;
2144
2145 if (colliding_ce == ce) {
2146 for (i = 0; i < current_trait; i++) {
2147 if (traits[i]
2148 && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2149 return traits[i];
2150 }
2151 }
2152 }
2153
2154 return colliding_ce;
2155 }
2156 /* }}} */
2157
zend_do_traits_property_binding(zend_class_entry * ce,zend_class_entry ** traits)2158 static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2159 {
2160 size_t i;
2161 zend_property_info *property_info;
2162 zend_property_info *colliding_prop;
2163 zend_property_info *new_prop;
2164 zend_string* prop_name;
2165 bool not_compatible;
2166 zval* prop_value;
2167 zend_string *doc_comment;
2168
2169 /* In the following steps the properties are inserted into the property table
2170 * for that, a very strict approach is applied:
2171 * - check for compatibility, if not compatible with any property in class -> fatal
2172 * - if compatible, then strict notice
2173 */
2174 for (i = 0; i < ce->num_traits; i++) {
2175 if (!traits[i]) {
2176 continue;
2177 }
2178 ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2179 uint32_t flags = property_info->flags;
2180
2181 /* next: check for conflicts with current class */
2182 if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2183 if ((colliding_prop->flags & ZEND_ACC_PRIVATE) && colliding_prop->ce != ce) {
2184 zend_hash_del(&ce->properties_info, prop_name);
2185 flags |= ZEND_ACC_CHANGED;
2186 } else {
2187 uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2188 not_compatible = 1;
2189
2190 if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2191 property_types_compatible(property_info, colliding_prop) == INHERITANCE_SUCCESS
2192 ) {
2193 /* the flags are identical, thus, the properties may be compatible */
2194 zval *op1, *op2;
2195 zval op1_tmp, op2_tmp;
2196
2197 if (flags & ZEND_ACC_STATIC) {
2198 op1 = &ce->default_static_members_table[colliding_prop->offset];
2199 op2 = &traits[i]->default_static_members_table[property_info->offset];
2200 ZVAL_DEINDIRECT(op1);
2201 ZVAL_DEINDIRECT(op2);
2202 } else {
2203 op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2204 op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2205 }
2206
2207 /* if any of the values is a constant, we try to resolve it */
2208 if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
2209 ZVAL_COPY_OR_DUP(&op1_tmp, op1);
2210 zval_update_constant_ex(&op1_tmp, ce);
2211 op1 = &op1_tmp;
2212 }
2213 if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
2214 ZVAL_COPY_OR_DUP(&op2_tmp, op2);
2215 zval_update_constant_ex(&op2_tmp, ce);
2216 op2 = &op2_tmp;
2217 }
2218
2219 not_compatible = fast_is_not_identical_function(op1, op2);
2220
2221 if (op1 == &op1_tmp) {
2222 zval_ptr_dtor_nogc(&op1_tmp);
2223 }
2224 if (op2 == &op2_tmp) {
2225 zval_ptr_dtor_nogc(&op2_tmp);
2226 }
2227 }
2228
2229 if (not_compatible) {
2230 zend_error_noreturn(E_COMPILE_ERROR,
2231 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2232 ZSTR_VAL(find_first_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2233 ZSTR_VAL(property_info->ce->name),
2234 ZSTR_VAL(prop_name),
2235 ZSTR_VAL(ce->name));
2236 }
2237 continue;
2238 }
2239 }
2240
2241 /* property not found, so lets add it */
2242 if (flags & ZEND_ACC_STATIC) {
2243 prop_value = &traits[i]->default_static_members_table[property_info->offset];
2244 ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2245 } else {
2246 prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2247 }
2248
2249 Z_TRY_ADDREF_P(prop_value);
2250 doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2251
2252 zend_type type = property_info->type;
2253 zend_type_copy_ctor(&type, /* persistent */ 0);
2254 new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2255
2256 if (property_info->attributes) {
2257 new_prop->attributes = property_info->attributes;
2258
2259 if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2260 GC_ADDREF(new_prop->attributes);
2261 }
2262 }
2263 } ZEND_HASH_FOREACH_END();
2264 }
2265 }
2266 /* }}} */
2267
zend_do_bind_traits(zend_class_entry * ce,zend_class_entry ** traits)2268 static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2269 {
2270 HashTable **exclude_tables;
2271 zend_class_entry **aliases;
2272
2273 ZEND_ASSERT(ce->num_traits > 0);
2274
2275 /* complete initialization of trait structures in ce */
2276 zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases);
2277
2278 /* first care about all methods to be flattened into the class */
2279 zend_do_traits_method_binding(ce, traits, exclude_tables, aliases);
2280
2281 if (aliases) {
2282 efree(aliases);
2283 }
2284
2285 if (exclude_tables) {
2286 efree(exclude_tables);
2287 }
2288
2289 /* then flatten the properties into it, to, mostly to notify developer about problems */
2290 zend_do_traits_property_binding(ce, traits);
2291 }
2292 /* }}} */
2293
2294 #define MAX_ABSTRACT_INFO_CNT 3
2295 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
2296 #define DISPLAY_ABSTRACT_FN(idx) \
2297 ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
2298 ai.afn[idx] ? "::" : "", \
2299 ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
2300 ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
2301
2302 typedef struct _zend_abstract_info {
2303 zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
2304 int cnt;
2305 } zend_abstract_info;
2306
zend_verify_abstract_class_function(zend_function * fn,zend_abstract_info * ai)2307 static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai) /* {{{ */
2308 {
2309 if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
2310 ai->afn[ai->cnt] = fn;
2311 }
2312 ai->cnt++;
2313 }
2314 /* }}} */
2315
zend_verify_abstract_class(zend_class_entry * ce)2316 void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
2317 {
2318 zend_function *func;
2319 zend_abstract_info ai;
2320 bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
2321 memset(&ai, 0, sizeof(ai));
2322
2323 ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
2324 if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
2325 /* If the class is explicitly abstract, we only check private abstract methods,
2326 * because only they must be declared in the same class. */
2327 if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
2328 zend_verify_abstract_class_function(func, &ai);
2329 }
2330 }
2331 } ZEND_HASH_FOREACH_END();
2332
2333 if (ai.cnt) {
2334 zend_error_noreturn(E_ERROR, !is_explicit_abstract
2335 ? "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")"
2336 : "Class %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
2337 ZSTR_VAL(ce->name), ai.cnt,
2338 ai.cnt > 1 ? "s" : "",
2339 DISPLAY_ABSTRACT_FN(0),
2340 DISPLAY_ABSTRACT_FN(1),
2341 DISPLAY_ABSTRACT_FN(2)
2342 );
2343 } else {
2344 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
2345 ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2346 }
2347 }
2348 /* }}} */
2349
2350 typedef struct {
2351 enum {
2352 OBLIGATION_DEPENDENCY,
2353 OBLIGATION_COMPATIBILITY,
2354 OBLIGATION_PROPERTY_COMPATIBILITY
2355 } type;
2356 union {
2357 zend_class_entry *dependency_ce;
2358 struct {
2359 /* Traits may use temporary on-stack functions during inheritance checks,
2360 * so use copies of functions here as well. */
2361 zend_function parent_fn;
2362 zend_function child_fn;
2363 zend_class_entry *child_scope;
2364 zend_class_entry *parent_scope;
2365 };
2366 struct {
2367 const zend_property_info *parent_prop;
2368 const zend_property_info *child_prop;
2369 };
2370 };
2371 } variance_obligation;
2372
variance_obligation_dtor(zval * zv)2373 static void variance_obligation_dtor(zval *zv) {
2374 efree(Z_PTR_P(zv));
2375 }
2376
variance_obligation_ht_dtor(zval * zv)2377 static void variance_obligation_ht_dtor(zval *zv) {
2378 zend_hash_destroy(Z_PTR_P(zv));
2379 FREE_HASHTABLE(Z_PTR_P(zv));
2380 }
2381
get_or_init_obligations_for_class(zend_class_entry * ce)2382 static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
2383 HashTable *ht;
2384 zend_ulong key;
2385 if (!CG(delayed_variance_obligations)) {
2386 ALLOC_HASHTABLE(CG(delayed_variance_obligations));
2387 zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
2388 }
2389
2390 key = (zend_ulong) (uintptr_t) ce;
2391 ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
2392 if (ht) {
2393 return ht;
2394 }
2395
2396 ALLOC_HASHTABLE(ht);
2397 zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
2398 zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
2399 ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
2400 return ht;
2401 }
2402
add_dependency_obligation(zend_class_entry * ce,zend_class_entry * dependency_ce)2403 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
2404 HashTable *obligations = get_or_init_obligations_for_class(ce);
2405 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2406 obligation->type = OBLIGATION_DEPENDENCY;
2407 obligation->dependency_ce = dependency_ce;
2408 zend_hash_next_index_insert_ptr(obligations, obligation);
2409 }
2410
add_compatibility_obligation(zend_class_entry * ce,const zend_function * child_fn,zend_class_entry * child_scope,const zend_function * parent_fn,zend_class_entry * parent_scope)2411 static void add_compatibility_obligation(
2412 zend_class_entry *ce,
2413 const zend_function *child_fn, zend_class_entry *child_scope,
2414 const zend_function *parent_fn, zend_class_entry *parent_scope) {
2415 HashTable *obligations = get_or_init_obligations_for_class(ce);
2416 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2417 obligation->type = OBLIGATION_COMPATIBILITY;
2418 /* Copy functions, because they may be stack-allocated in the case of traits. */
2419 if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
2420 memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
2421 } else {
2422 memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
2423 }
2424 if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
2425 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
2426 } else {
2427 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
2428 }
2429 obligation->child_scope = child_scope;
2430 obligation->parent_scope = parent_scope;
2431 zend_hash_next_index_insert_ptr(obligations, obligation);
2432 }
2433
add_property_compatibility_obligation(zend_class_entry * ce,const zend_property_info * child_prop,const zend_property_info * parent_prop)2434 static void add_property_compatibility_obligation(
2435 zend_class_entry *ce, const zend_property_info *child_prop,
2436 const zend_property_info *parent_prop) {
2437 HashTable *obligations = get_or_init_obligations_for_class(ce);
2438 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2439 obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
2440 obligation->child_prop = child_prop;
2441 obligation->parent_prop = parent_prop;
2442 zend_hash_next_index_insert_ptr(obligations, obligation);
2443 }
2444
2445 static void resolve_delayed_variance_obligations(zend_class_entry *ce);
2446
check_variance_obligation(variance_obligation * obligation)2447 static void check_variance_obligation(variance_obligation *obligation) {
2448 if (obligation->type == OBLIGATION_DEPENDENCY) {
2449 zend_class_entry *dependency_ce = obligation->dependency_ce;
2450 if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
2451 zend_class_entry *orig_linking_class = CG(current_linking_class);
2452
2453 CG(current_linking_class) =
2454 (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
2455 resolve_delayed_variance_obligations(dependency_ce);
2456 CG(current_linking_class) = orig_linking_class;
2457 }
2458 } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
2459 inheritance_status status = zend_do_perform_implementation_check(
2460 &obligation->child_fn, obligation->child_scope,
2461 &obligation->parent_fn, obligation->parent_scope);
2462 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
2463 emit_incompatible_method_error(
2464 &obligation->child_fn, obligation->child_scope,
2465 &obligation->parent_fn, obligation->parent_scope, status);
2466 }
2467 /* Either the compatibility check was successful or only threw a warning. */
2468 } else {
2469 ZEND_ASSERT(obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY);
2470 inheritance_status status =
2471 property_types_compatible(obligation->parent_prop, obligation->child_prop);
2472 if (status != INHERITANCE_SUCCESS) {
2473 emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop);
2474 }
2475 }
2476 }
2477
load_delayed_classes(zend_class_entry * ce)2478 static void load_delayed_classes(zend_class_entry *ce) {
2479 HashTable *delayed_autoloads = CG(delayed_autoloads);
2480 if (!delayed_autoloads) {
2481 return;
2482 }
2483
2484 /* Autoloading can trigger linking of another class, which may register new delayed autoloads.
2485 * For that reason, this code uses a loop that pops and loads the first element of the HT. If
2486 * this triggers linking, then the remaining classes may get loaded when linking the newly
2487 * loaded class. This is important, as otherwise necessary dependencies may not be available
2488 * if the new class is lower in the hierarchy than the current one. */
2489 HashPosition pos = 0;
2490 zend_string *name;
2491 zend_ulong idx;
2492 while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
2493 != HASH_KEY_NON_EXISTENT) {
2494 zend_string_addref(name);
2495 zend_hash_del(delayed_autoloads, name);
2496 zend_lookup_class(name);
2497 zend_string_release(name);
2498 if (EG(exception)) {
2499 zend_exception_uncaught_error(
2500 "During inheritance of %s, while autoloading %s",
2501 ZSTR_VAL(ce->name), ZSTR_VAL(name));
2502 }
2503 }
2504 }
2505
resolve_delayed_variance_obligations(zend_class_entry * ce)2506 static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
2507 HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
2508 zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
2509
2510 ZEND_ASSERT(all_obligations != NULL);
2511 obligations = zend_hash_index_find_ptr(all_obligations, num_key);
2512 ZEND_ASSERT(obligations != NULL);
2513
2514 variance_obligation *obligation;
2515 ZEND_HASH_FOREACH_PTR(obligations, obligation) {
2516 check_variance_obligation(obligation);
2517 } ZEND_HASH_FOREACH_END();
2518
2519 ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
2520 ce->ce_flags |= ZEND_ACC_LINKED;
2521 zend_hash_index_del(all_obligations, num_key);
2522 }
2523
check_unrecoverable_load_failure(zend_class_entry * ce)2524 static void check_unrecoverable_load_failure(zend_class_entry *ce) {
2525 /* If this class has been used while unlinked through a variance obligation, it is not legal
2526 * to remove the class from the class table and throw an exception, because there is already
2527 * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
2528 * a fatal error, as would happen if we did not allow exceptions in the first place. */
2529 if (CG(unlinked_uses)
2530 && zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce) == SUCCESS) {
2531 zend_exception_uncaught_error(
2532 "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
2533 }
2534 }
2535
2536 #define zend_update_inherited_handler(handler) do { \
2537 if (ce->handler == (zend_function*)op_array) { \
2538 ce->handler = (zend_function*)new_op_array; \
2539 } \
2540 } while (0)
2541
zend_lazy_class_load(zend_class_entry * pce)2542 static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
2543 {
2544 zend_class_entry *ce;
2545 Bucket *p, *end;
2546
2547 ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
2548 memcpy(ce, pce, sizeof(zend_class_entry));
2549 ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
2550 ce->refcount = 1;
2551 ce->inheritance_cache = NULL;
2552 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
2553 ZEND_MAP_PTR_NEW(ce->mutable_data);
2554 } else {
2555 ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
2556 }
2557
2558 /* properties */
2559 if (ce->default_properties_table) {
2560 zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
2561 zval *src = ce->default_properties_table;
2562 zval *end = src + ce->default_properties_count;
2563
2564 ce->default_properties_table = dst;
2565 for (; src != end; src++, dst++) {
2566 ZVAL_COPY_VALUE_PROP(dst, src);
2567 }
2568 }
2569
2570 /* methods */
2571 ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
2572 if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
2573 p = emalloc(HT_SIZE(&ce->function_table));
2574 memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
2575 HT_SET_DATA_ADDR(&ce->function_table, p);
2576 p = ce->function_table.arData;
2577 end = p + ce->function_table.nNumUsed;
2578 for (; p != end; p++) {
2579 zend_op_array *op_array, *new_op_array;
2580 void ***run_time_cache_ptr;
2581 size_t alloc_size;
2582
2583 op_array = Z_PTR(p->val);
2584 ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
2585 ZEND_ASSERT(op_array->scope == pce);
2586 ZEND_ASSERT(op_array->prototype == NULL);
2587 alloc_size = sizeof(zend_op_array) + sizeof(void *);
2588 if (op_array->static_variables) {
2589 alloc_size += sizeof(HashTable *);
2590 }
2591 new_op_array = zend_arena_alloc(&CG(arena), alloc_size);
2592 Z_PTR(p->val) = new_op_array;
2593 memcpy(new_op_array, op_array, sizeof(zend_op_array));
2594 run_time_cache_ptr = (void***)(new_op_array + 1);
2595 *run_time_cache_ptr = NULL;
2596 new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
2597 new_op_array->scope = ce;
2598 ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, run_time_cache_ptr);
2599 if (op_array->static_variables) {
2600 HashTable **static_variables_ptr = (HashTable **) (run_time_cache_ptr + 1);
2601 *static_variables_ptr = NULL;
2602 ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, static_variables_ptr);
2603 }
2604
2605 zend_update_inherited_handler(constructor);
2606 zend_update_inherited_handler(destructor);
2607 zend_update_inherited_handler(clone);
2608 zend_update_inherited_handler(__get);
2609 zend_update_inherited_handler(__set);
2610 zend_update_inherited_handler(__call);
2611 zend_update_inherited_handler(__isset);
2612 zend_update_inherited_handler(__unset);
2613 zend_update_inherited_handler(__tostring);
2614 zend_update_inherited_handler(__callstatic);
2615 zend_update_inherited_handler(__debugInfo);
2616 zend_update_inherited_handler(__serialize);
2617 zend_update_inherited_handler(__unserialize);
2618 }
2619 }
2620
2621 /* static members */
2622 if (ce->default_static_members_table) {
2623 zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
2624 zval *src = ce->default_static_members_table;
2625 zval *end = src + ce->default_static_members_count;
2626
2627 ce->default_static_members_table = dst;
2628 for (; src != end; src++, dst++) {
2629 ZVAL_COPY_VALUE(dst, src);
2630 }
2631 }
2632 ZEND_MAP_PTR_INIT(ce->static_members_table, zend_arena_alloc(&CG(arena), sizeof(zval *)));
2633 ZEND_MAP_PTR_SET(ce->static_members_table, NULL);
2634
2635 /* properties_info */
2636 if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
2637 p = emalloc(HT_SIZE(&ce->properties_info));
2638 memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
2639 HT_SET_DATA_ADDR(&ce->properties_info, p);
2640 p = ce->properties_info.arData;
2641 end = p + ce->properties_info.nNumUsed;
2642 for (; p != end; p++) {
2643 zend_property_info *prop_info, *new_prop_info;
2644
2645 prop_info = Z_PTR(p->val);
2646 ZEND_ASSERT(prop_info->ce == pce);
2647 new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
2648 Z_PTR(p->val) = new_prop_info;
2649 memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
2650 new_prop_info->ce = ce;
2651 if (ZEND_TYPE_HAS_LIST(new_prop_info->type)) {
2652 zend_type_list *new_list;
2653 zend_type_list *list = ZEND_TYPE_LIST(new_prop_info->type);
2654
2655 new_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(list->num_types));
2656 memcpy(new_list, list, ZEND_TYPE_LIST_SIZE(list->num_types));
2657 ZEND_TYPE_SET_PTR(new_prop_info->type, list);
2658 ZEND_TYPE_FULL_MASK(new_prop_info->type) |= _ZEND_TYPE_ARENA_BIT;
2659 }
2660 }
2661 }
2662
2663 /* constants table */
2664 if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
2665 p = emalloc(HT_SIZE(&ce->constants_table));
2666 memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
2667 HT_SET_DATA_ADDR(&ce->constants_table, p);
2668 p = ce->constants_table.arData;
2669 end = p + ce->constants_table.nNumUsed;
2670 for (; p != end; p++) {
2671 zend_class_constant *c, *new_c;
2672
2673 c = Z_PTR(p->val);
2674 ZEND_ASSERT(c->ce == pce);
2675 new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2676 Z_PTR(p->val) = new_c;
2677 memcpy(new_c, c, sizeof(zend_class_constant));
2678 new_c->ce = ce;
2679 }
2680 }
2681
2682 return ce;
2683 }
2684
2685 #ifndef ZEND_WIN32
2686 # define UPDATE_IS_CACHEABLE(ce) do { \
2687 if ((ce)->type == ZEND_USER_CLASS) { \
2688 is_cacheable &= (ce)->ce_flags; \
2689 } \
2690 } while (0)
2691 #else
2692 // TODO: ASLR may cause different addresses in different workers ???
2693 # define UPDATE_IS_CACHEABLE(ce) do { \
2694 is_cacheable &= (ce)->ce_flags; \
2695 } while (0)
2696 #endif
2697
zend_do_link_class(zend_class_entry * ce,zend_string * lc_parent_name,zend_string * key)2698 ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key) /* {{{ */
2699 {
2700 /* Load parent/interface dependencies first, so we can still gracefully abort linking
2701 * with an exception and remove the class from the class table. This is only possible
2702 * if no variance obligations on the current class have been added during autoloading. */
2703 zend_class_entry *parent = NULL;
2704 zend_class_entry **traits_and_interfaces = NULL;
2705 zend_class_entry *proto = NULL;
2706 zend_class_entry *orig_linking_class;
2707 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
2708 uint32_t i, j;
2709 zval *zv;
2710 ALLOCA_FLAG(use_heap)
2711
2712 SET_ALLOCA_FLAG(use_heap);
2713 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
2714
2715 if (ce->parent_name) {
2716 parent = zend_fetch_class_by_name(
2717 ce->parent_name, lc_parent_name,
2718 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
2719 if (!parent) {
2720 check_unrecoverable_load_failure(ce);
2721 return NULL;
2722 }
2723 UPDATE_IS_CACHEABLE(parent);
2724 }
2725
2726 if (ce->num_traits || ce->num_interfaces) {
2727 traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
2728
2729 for (i = 0; i < ce->num_traits; i++) {
2730 zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
2731 ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
2732 if (UNEXPECTED(trait == NULL)) {
2733 free_alloca(traits_and_interfaces, use_heap);
2734 return NULL;
2735 }
2736 if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
2737 zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
2738 free_alloca(traits_and_interfaces, use_heap);
2739 return NULL;
2740 }
2741 for (j = 0; j < i; j++) {
2742 if (traits_and_interfaces[j] == trait) {
2743 /* skip duplications */
2744 trait = NULL;
2745 break;
2746 }
2747 }
2748 traits_and_interfaces[i] = trait;
2749 if (trait) {
2750 UPDATE_IS_CACHEABLE(trait);
2751 }
2752 }
2753 }
2754
2755 if (ce->num_interfaces) {
2756 for (i = 0; i < ce->num_interfaces; i++) {
2757 zend_class_entry *iface = zend_fetch_class_by_name(
2758 ce->interface_names[i].name, ce->interface_names[i].lc_name,
2759 ZEND_FETCH_CLASS_INTERFACE |
2760 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
2761 if (!iface) {
2762 check_unrecoverable_load_failure(ce);
2763 free_alloca(traits_and_interfaces, use_heap);
2764 return NULL;
2765 }
2766 traits_and_interfaces[ce->num_traits + i] = iface;
2767 if (iface) {
2768 UPDATE_IS_CACHEABLE(iface);
2769 }
2770 }
2771 }
2772
2773 #ifndef ZEND_WIN32
2774 if (ce->ce_flags & ZEND_ACC_ENUM) {
2775 /* We will add internal methods. */
2776 is_cacheable = false;
2777 }
2778 #endif
2779
2780 bool orig_record_errors = EG(record_errors);
2781
2782 if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
2783 if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
2784 zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
2785 if (ret) {
2786 if (traits_and_interfaces) {
2787 free_alloca(traits_and_interfaces, use_heap);
2788 }
2789 zv = zend_hash_find_known_hash(CG(class_table), key);
2790 Z_CE_P(zv) = ret;
2791 return ret;
2792 }
2793
2794 /* Make sure warnings (such as deprecations) thrown during inheritance
2795 * will be recorded in the inheritance cache. */
2796 zend_begin_record_errors();
2797 } else {
2798 is_cacheable = 0;
2799 }
2800 proto = ce;
2801 }
2802
2803 zend_try {
2804 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
2805 /* Lazy class loading */
2806 ce = zend_lazy_class_load(ce);
2807 zv = zend_hash_find_known_hash(CG(class_table), key);
2808 Z_CE_P(zv) = ce;
2809 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
2810 /* Lazy class loading */
2811 ce = zend_lazy_class_load(ce);
2812 ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
2813 zv = zend_hash_find_known_hash(CG(class_table), key);
2814 Z_CE_P(zv) = ce;
2815 }
2816
2817 if (CG(unlinked_uses)) {
2818 zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t) ce);
2819 }
2820
2821 orig_linking_class = CG(current_linking_class);
2822 CG(current_linking_class) = is_cacheable ? ce : NULL;
2823
2824 if (ce->ce_flags & ZEND_ACC_ENUM) {
2825 /* Only register builtin enum methods during inheritance to avoid persisting them in
2826 * opcache. */
2827 zend_enum_register_funcs(ce);
2828 }
2829
2830 if (parent) {
2831 if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
2832 add_dependency_obligation(ce, parent);
2833 }
2834 zend_do_inheritance(ce, parent);
2835 }
2836 if (ce->num_traits) {
2837 zend_do_bind_traits(ce, traits_and_interfaces);
2838 }
2839 if (ce->num_interfaces) {
2840 /* Also copy the parent interfaces here, so we don't need to reallocate later. */
2841 uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
2842 zend_class_entry **interfaces = emalloc(
2843 sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
2844
2845 if (num_parent_interfaces) {
2846 memcpy(interfaces, parent->interfaces,
2847 sizeof(zend_class_entry *) * num_parent_interfaces);
2848 }
2849 memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
2850 sizeof(zend_class_entry *) * ce->num_interfaces);
2851
2852 zend_do_implement_interfaces(ce, interfaces);
2853 } else if (parent && parent->num_interfaces) {
2854 zend_do_inherit_interfaces(ce, parent);
2855 }
2856 if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
2857 && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
2858 ) {
2859 zend_verify_abstract_class(ce);
2860 }
2861 if (ce->ce_flags & ZEND_ACC_ENUM) {
2862 zend_verify_enum(ce);
2863 }
2864
2865 /* Normally Stringable is added during compilation. However, if it is imported from a trait,
2866 * we need to explicilty add the interface here. */
2867 if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
2868 && !zend_class_implements_interface(ce, zend_ce_stringable)) {
2869 ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
2870 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2871 ce->num_interfaces++;
2872 ce->interfaces = perealloc(ce->interfaces,
2873 sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
2874 ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
2875 do_interface_implementation(ce, zend_ce_stringable);
2876 }
2877
2878 zend_build_properties_info_table(ce);
2879 } zend_catch {
2880 /* Do not leak recorded errors to the next linked class. */
2881 if (!orig_record_errors) {
2882 EG(record_errors) = false;
2883 zend_free_recorded_errors();
2884 }
2885 zend_bailout();
2886 } zend_end_try();
2887
2888 EG(record_errors) = orig_record_errors;
2889
2890 if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
2891 ce->ce_flags |= ZEND_ACC_LINKED;
2892 } else {
2893 ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
2894 if (CG(current_linking_class)) {
2895 ce->ce_flags |= ZEND_ACC_CACHEABLE;
2896 }
2897 load_delayed_classes(ce);
2898 if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
2899 resolve_delayed_variance_obligations(ce);
2900 }
2901 if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
2902 ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
2903 } else {
2904 CG(current_linking_class) = NULL;
2905 }
2906 }
2907
2908 if (!CG(current_linking_class)) {
2909 is_cacheable = 0;
2910 }
2911 CG(current_linking_class) = orig_linking_class;
2912
2913 if (is_cacheable) {
2914 HashTable *ht = (HashTable*)ce->inheritance_cache;
2915 zend_class_entry *new_ce;
2916
2917 ce->inheritance_cache = NULL;
2918 new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
2919 if (new_ce) {
2920 zv = zend_hash_find_known_hash(CG(class_table), key);
2921 ce = new_ce;
2922 Z_CE_P(zv) = ce;
2923 }
2924 if (ht) {
2925 zend_hash_destroy(ht);
2926 FREE_HASHTABLE(ht);
2927 }
2928 }
2929
2930 if (!orig_record_errors) {
2931 zend_free_recorded_errors();
2932 }
2933 if (traits_and_interfaces) {
2934 free_alloca(traits_and_interfaces, use_heap);
2935 }
2936
2937 if (ZSTR_HAS_CE_CACHE(ce->name)) {
2938 ZSTR_SET_CE_CACHE(ce->name, ce);
2939 }
2940
2941 return ce;
2942 }
2943 /* }}} */
2944
2945 /* Check whether early binding is prevented due to unresolved types in inheritance checks. */
zend_can_early_bind(zend_class_entry * ce,zend_class_entry * parent_ce)2946 static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
2947 {
2948 zend_string *key;
2949 zend_function *parent_func;
2950 zend_property_info *parent_info;
2951 inheritance_status overall_status = INHERITANCE_SUCCESS;
2952
2953 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
2954 zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
2955 if (zv) {
2956 zend_function *child_func = Z_FUNC_P(zv);
2957 inheritance_status status =
2958 do_inheritance_check_on_method_ex(
2959 child_func, child_func->common.scope,
2960 parent_func, parent_func->common.scope,
2961 ce, NULL, /* check_visibility */ 1, 1, 0);
2962 if (UNEXPECTED(status == INHERITANCE_WARNING)) {
2963 overall_status = INHERITANCE_WARNING;
2964 } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
2965 return status;
2966 }
2967 }
2968 } ZEND_HASH_FOREACH_END();
2969
2970 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
2971 zval *zv;
2972 if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
2973 continue;
2974 }
2975
2976 zv = zend_hash_find_known_hash(&ce->properties_info, key);
2977 if (zv) {
2978 zend_property_info *child_info = Z_PTR_P(zv);
2979 if (ZEND_TYPE_IS_SET(child_info->type)) {
2980 inheritance_status status = property_types_compatible(parent_info, child_info);
2981 ZEND_ASSERT(status != INHERITANCE_WARNING);
2982 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
2983 return status;
2984 }
2985 }
2986 }
2987 } ZEND_HASH_FOREACH_END();
2988
2989 return overall_status;
2990 }
2991 /* }}} */
2992
register_early_bound_ce(zval * delayed_early_binding,zend_string * lcname,zend_class_entry * ce)2993 static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
2994 if (delayed_early_binding) {
2995 if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
2996 if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
2997 Z_CE_P(delayed_early_binding) = ce;
2998 return true;
2999 }
3000 } else {
3001 /* If preloading is used, don't replace the existing bucket, add a new one. */
3002 if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3003 return true;
3004 }
3005 }
3006 zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
3007 return false;
3008 }
3009 return zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL;
3010 }
3011
zend_try_early_bind(zend_class_entry * ce,zend_class_entry * parent_ce,zend_string * lcname,zval * delayed_early_binding)3012 zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding) /* {{{ */
3013 {
3014 inheritance_status status;
3015 zend_class_entry *proto = NULL;
3016 zend_class_entry *orig_linking_class;
3017 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3018
3019 UPDATE_IS_CACHEABLE(parent_ce);
3020 if (is_cacheable) {
3021 if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3022 zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3023 if (ret) {
3024 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
3025 return NULL;
3026 }
3027 return ret;
3028 }
3029 } else {
3030 is_cacheable = 0;
3031 }
3032 proto = ce;
3033 }
3034
3035 orig_linking_class = CG(current_linking_class);
3036 CG(current_linking_class) = NULL;
3037 status = zend_can_early_bind(ce, parent_ce);
3038 CG(current_linking_class) = orig_linking_class;
3039 if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3040 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3041 /* Lazy class loading */
3042 ce = zend_lazy_class_load(ce);
3043 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3044 /* Lazy class loading */
3045 ce = zend_lazy_class_load(ce);
3046 ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3047 }
3048
3049 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3050 return NULL;
3051 }
3052
3053 orig_linking_class = CG(current_linking_class);
3054 CG(current_linking_class) = is_cacheable ? ce : NULL;
3055
3056 zend_try{
3057 if (is_cacheable) {
3058 zend_begin_record_errors();
3059 }
3060
3061 zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3062 if (parent_ce && parent_ce->num_interfaces) {
3063 zend_do_inherit_interfaces(ce, parent_ce);
3064 }
3065 zend_build_properties_info_table(ce);
3066 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) {
3067 zend_verify_abstract_class(ce);
3068 }
3069 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3070 ce->ce_flags |= ZEND_ACC_LINKED;
3071
3072 CG(current_linking_class) = orig_linking_class;
3073 } zend_catch {
3074 EG(record_errors) = false;
3075 zend_free_recorded_errors();
3076 zend_bailout();
3077 } zend_end_try();
3078
3079 EG(record_errors) = false;
3080
3081 if (is_cacheable) {
3082 HashTable *ht = (HashTable*)ce->inheritance_cache;
3083 zend_class_entry *new_ce;
3084
3085 ce->inheritance_cache = NULL;
3086 new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3087 if (new_ce) {
3088 zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3089 ce = new_ce;
3090 Z_CE_P(zv) = ce;
3091 }
3092 if (ht) {
3093 zend_hash_destroy(ht);
3094 FREE_HASHTABLE(ht);
3095 }
3096 }
3097
3098 if (ZSTR_HAS_CE_CACHE(ce->name)) {
3099 ZSTR_SET_CE_CACHE(ce->name, ce);
3100 }
3101
3102 return ce;
3103 }
3104 return NULL;
3105 }
3106 /* }}} */
3107