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