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