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))) {
1761 /* Class must not extend a final class */
1762 if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1763 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1764 }
1765
1766 /* Class declaration must not extend traits or interfaces */
1767 if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1768 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1769 ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1770 );
1771 }
1772 }
1773
1774 if (UNEXPECTED((ce->ce_flags & ZEND_ACC_READONLY_CLASS) != (parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS))) {
1775 zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1776 ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1777 parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1778 );
1779 }
1780
1781 if (ce->parent_name) {
1782 zend_string_release_ex(ce->parent_name, 0);
1783 }
1784 ce->parent = parent_ce;
1785 ce->default_object_handlers = parent_ce->default_object_handlers;
1786 ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1787
1788 /* Inherit properties */
1789 if (parent_ce->default_properties_count) {
1790 zval *src, *dst, *end;
1791
1792 if (ce->default_properties_count) {
1793 zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1794 src = ce->default_properties_table + ce->default_properties_count;
1795 end = table + parent_ce->default_properties_count;
1796 dst = end + ce->default_properties_count;
1797 ce->default_properties_table = table;
1798 do {
1799 dst--;
1800 src--;
1801 ZVAL_COPY_VALUE_PROP(dst, src);
1802 } while (dst != end);
1803 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1804 end = ce->default_properties_table;
1805 } else {
1806 end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1807 dst = end + parent_ce->default_properties_count;
1808 ce->default_properties_table = end;
1809 }
1810 src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1811 if (UNEXPECTED(parent_ce->type != ce->type)) {
1812 /* User class extends internal */
1813 do {
1814 dst--;
1815 src--;
1816 /* We don't have to account for refcounting because
1817 * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1818 ZEND_ASSERT(!Z_REFCOUNTED_P(src));
1819 ZVAL_COPY_VALUE_PROP(dst, src);
1820 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1821 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1822 ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1823 }
1824 continue;
1825 } while (dst != end);
1826 } else {
1827 do {
1828 dst--;
1829 src--;
1830 ZVAL_COPY_PROP(dst, src);
1831 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1832 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1833 ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1834 }
1835 continue;
1836 } while (dst != end);
1837 }
1838 ce->default_properties_count += parent_ce->default_properties_count;
1839 }
1840
1841 if (parent_ce->default_static_members_count) {
1842 zval *src, *dst, *end;
1843
1844 if (ce->default_static_members_count) {
1845 zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1846 src = ce->default_static_members_table + ce->default_static_members_count;
1847 end = table + parent_ce->default_static_members_count;
1848 dst = end + ce->default_static_members_count;
1849 ce->default_static_members_table = table;
1850 do {
1851 dst--;
1852 src--;
1853 ZVAL_COPY_VALUE(dst, src);
1854 } while (dst != end);
1855 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1856 end = ce->default_static_members_table;
1857 } else {
1858 end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1859 dst = end + parent_ce->default_static_members_count;
1860 ce->default_static_members_table = end;
1861 }
1862 src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1863 do {
1864 dst--;
1865 src--;
1866 if (Z_TYPE_P(src) == IS_INDIRECT) {
1867 ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1868 } else {
1869 ZVAL_INDIRECT(dst, src);
1870 }
1871 if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1872 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1873 ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
1874 }
1875 } while (dst != end);
1876 ce->default_static_members_count += parent_ce->default_static_members_count;
1877 if (!ZEND_MAP_PTR(ce->static_members_table)) {
1878 if (ce->type == ZEND_INTERNAL_CLASS &&
1879 ce->info.internal.module->type == MODULE_PERSISTENT) {
1880 ZEND_MAP_PTR_NEW(ce->static_members_table);
1881 }
1882 }
1883 }
1884
1885 ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1886 if (property_info->ce == ce) {
1887 if (property_info->flags & ZEND_ACC_STATIC) {
1888 property_info->offset += parent_ce->default_static_members_count;
1889 } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1890 property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1891 }
1892 }
1893 } ZEND_HASH_FOREACH_END();
1894
1895 if (zend_hash_num_elements(&parent_ce->properties_info)) {
1896 zend_hash_extend(&ce->properties_info,
1897 zend_hash_num_elements(&ce->properties_info) +
1898 zend_hash_num_elements(&parent_ce->properties_info), 0);
1899
1900 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1901 do_inherit_property(property_info, key, ce);
1902 } ZEND_HASH_FOREACH_END();
1903 }
1904
1905 if (ce->num_hooked_props) {
1906 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
1907 if (property_info->ce == ce && property_info->hooks) {
1908 zend_verify_hooked_property(ce, property_info, key);
1909 }
1910 } ZEND_HASH_FOREACH_END();
1911 }
1912
1913 if (zend_hash_num_elements(&parent_ce->constants_table)) {
1914 zend_class_constant *c;
1915
1916 zend_hash_extend(&ce->constants_table,
1917 zend_hash_num_elements(&ce->constants_table) +
1918 zend_hash_num_elements(&parent_ce->constants_table), 0);
1919
1920 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
1921 do_inherit_class_constant(key, c, ce);
1922 } ZEND_HASH_FOREACH_END();
1923 }
1924
1925 if (zend_hash_num_elements(&parent_ce->function_table)) {
1926 zend_hash_extend(&ce->function_table,
1927 zend_hash_num_elements(&ce->function_table) +
1928 zend_hash_num_elements(&parent_ce->function_table), 0);
1929 uint32_t flags =
1930 ZEND_INHERITANCE_LAZY_CHILD_CLONE |
1931 ZEND_INHERITANCE_SET_CHILD_CHANGED |
1932 ZEND_INHERITANCE_SET_CHILD_PROTO |
1933 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
1934
1935 if (!checked) {
1936 flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
1937 }
1938 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1939 do_inherit_method(key, func, ce, 0, flags);
1940 } ZEND_HASH_FOREACH_END();
1941 }
1942
1943 do_inherit_parent_constructor(ce);
1944
1945 if (ce->type == ZEND_INTERNAL_CLASS) {
1946 if (parent_ce->num_interfaces) {
1947 zend_do_inherit_interfaces(ce, parent_ce);
1948 }
1949
1950 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1951 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1952 }
1953 }
1954 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);
1955 }
1956 /* }}} */
1957
check_trait_property_or_constant_value_compatibility(zend_class_entry * ce,zval * op1,zval * op2)1958 static zend_always_inline bool check_trait_property_or_constant_value_compatibility(zend_class_entry *ce, zval *op1, zval *op2) /* {{{ */
1959 {
1960 bool is_compatible;
1961 zval op1_tmp, op2_tmp;
1962
1963 /* if any of the values is a constant, we try to resolve it */
1964 if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
1965 ZVAL_COPY_OR_DUP(&op1_tmp, op1);
1966 if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
1967 zval_ptr_dtor(&op1_tmp);
1968 return false;
1969 }
1970 op1 = &op1_tmp;
1971 }
1972 if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
1973 ZVAL_COPY_OR_DUP(&op2_tmp, op2);
1974 if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
1975 zval_ptr_dtor(&op2_tmp);
1976 return false;
1977 }
1978 op2 = &op2_tmp;
1979 }
1980
1981 is_compatible = fast_is_identical_function(op1, op2);
1982
1983 if (op1 == &op1_tmp) {
1984 zval_ptr_dtor_nogc(&op1_tmp);
1985 }
1986 if (op2 == &op2_tmp) {
1987 zval_ptr_dtor_nogc(&op2_tmp);
1988 }
1989
1990 return is_compatible;
1991 }
1992 /* }}} */
1993
1994 /** @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)1995 static bool do_inherit_constant_check(
1996 zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name
1997 ) {
1998 zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1999 if (zv == NULL) {
2000 return true;
2001 }
2002
2003 zend_class_constant *child_constant = Z_PTR_P(zv);
2004 if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
2005 zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
2006 ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2007 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
2008 );
2009 }
2010
2011 if (child_constant->ce != parent_constant->ce && child_constant->ce != ce) {
2012 zend_error_noreturn(E_COMPILE_ERROR,
2013 "%s %s inherits both %s::%s and %s::%s, which is ambiguous",
2014 zend_get_object_type_uc(ce),
2015 ZSTR_VAL(ce->name),
2016 ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2017 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
2018 }
2019
2020 if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(child_constant) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PPP_MASK))) {
2021 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in %s %s)%s",
2022 ZSTR_VAL(ce->name), ZSTR_VAL(name),
2023 zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_constant)),
2024 zend_get_object_type(parent_constant->ce),
2025 ZSTR_VAL(parent_constant->ce->name),
2026 (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PUBLIC) ? "" : " or weaker"
2027 );
2028 }
2029
2030 if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
2031 inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
2032 if (status == INHERITANCE_ERROR) {
2033 emit_incompatible_class_constant_error(child_constant, parent_constant, name);
2034 } else if (status == INHERITANCE_UNRESOLVED) {
2035 add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
2036 }
2037 }
2038
2039 return false;
2040 }
2041 /* }}} */
2042
do_inherit_iface_constant(zend_string * name,zend_class_constant * c,zend_class_entry * ce,zend_class_entry * iface)2043 static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2044 {
2045 if (do_inherit_constant_check(ce, c, name)) {
2046 zend_class_constant *ct;
2047 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2048 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2049 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2050 if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
2051 ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2052 memcpy(ct, c, sizeof(zend_class_constant));
2053 c = ct;
2054 Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2055 }
2056 }
2057 if (ce->type & ZEND_INTERNAL_CLASS) {
2058 ct = pemalloc(sizeof(zend_class_constant), 1);
2059 memcpy(ct, c, sizeof(zend_class_constant));
2060 c = ct;
2061 }
2062 zend_hash_update_ptr(&ce->constants_table, name, c);
2063 }
2064 }
2065 /* }}} */
2066
do_interface_implementation(zend_class_entry * ce,zend_class_entry * iface)2067 static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2068 {
2069 zend_function *func;
2070 zend_string *key;
2071 zend_class_constant *c;
2072 uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2073
2074 if (!(ce->ce_flags & ZEND_ACC_INTERFACE)) {
2075 /* We are not setting the prototype of overridden interface methods because of abstract
2076 * constructors. See Zend/tests/interface_constructor_prototype_001.phpt. */
2077 flags |=
2078 ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2079 ZEND_INHERITANCE_SET_CHILD_PROTO |
2080 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2081 } else {
2082 flags |=
2083 ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2084 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2085 }
2086
2087 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2088 do_inherit_iface_constant(key, c, ce, iface);
2089 } ZEND_HASH_FOREACH_END();
2090
2091 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2092 do_inherit_method(key, func, ce, 1, flags);
2093 } ZEND_HASH_FOREACH_END();
2094
2095 zend_hash_extend(&ce->properties_info,
2096 zend_hash_num_elements(&ce->properties_info) +
2097 zend_hash_num_elements(&iface->properties_info), 0);
2098
2099 zend_property_info *prop;
2100 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2101 do_inherit_property(prop, key, ce);
2102 } ZEND_HASH_FOREACH_END();
2103
2104 do_implement_interface(ce, iface);
2105 if (iface->num_interfaces) {
2106 zend_do_inherit_interfaces(ce, iface);
2107 }
2108 }
2109 /* }}} */
2110
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)2111 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2112 {
2113 uint32_t i, ignore = 0;
2114 uint32_t current_iface_num = ce->num_interfaces;
2115 uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
2116 zend_string *key;
2117 zend_class_constant *c;
2118
2119 ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2120
2121 for (i = 0; i < ce->num_interfaces; i++) {
2122 if (ce->interfaces[i] == NULL) {
2123 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
2124 i--;
2125 } else if (ce->interfaces[i] == iface) {
2126 if (EXPECTED(i < parent_iface_num)) {
2127 ignore = 1;
2128 } else {
2129 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2130 }
2131 }
2132 }
2133 if (ignore) {
2134 /* Check for attempt to redeclare interface constants */
2135 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2136 do_inherit_constant_check(ce, c, key);
2137 } ZEND_HASH_FOREACH_END();
2138 } else {
2139 if (ce->num_interfaces >= current_iface_num) {
2140 if (ce->type == ZEND_INTERNAL_CLASS) {
2141 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2142 } else {
2143 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2144 }
2145 }
2146 ce->interfaces[ce->num_interfaces++] = iface;
2147
2148 do_interface_implementation(ce, iface);
2149 }
2150 }
2151 /* }}} */
2152
zend_do_implement_interfaces(zend_class_entry * ce,zend_class_entry ** interfaces)2153 static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
2154 {
2155 zend_class_entry *iface;
2156 uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2157 uint32_t num_interfaces = num_parent_interfaces;
2158 zend_string *key;
2159 zend_class_constant *c;
2160 uint32_t i, j;
2161
2162 for (i = 0; i < ce->num_interfaces; i++) {
2163 iface = interfaces[num_parent_interfaces + i];
2164 if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2165 add_dependency_obligation(ce, iface);
2166 }
2167 if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
2168 efree(interfaces);
2169 zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2170 return;
2171 }
2172 for (j = 0; j < num_interfaces; j++) {
2173 if (interfaces[j] == iface) {
2174 if (j >= num_parent_interfaces) {
2175 efree(interfaces);
2176 zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
2177 zend_get_object_type_uc(ce),
2178 ZSTR_VAL(ce->name),
2179 ZSTR_VAL(iface->name));
2180 return;
2181 }
2182 /* skip duplications */
2183 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2184 do_inherit_constant_check(ce, c, key);
2185 } ZEND_HASH_FOREACH_END();
2186
2187 iface = NULL;
2188 break;
2189 }
2190 }
2191 if (iface) {
2192 interfaces[num_interfaces] = iface;
2193 num_interfaces++;
2194 }
2195 }
2196
2197 if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2198 for (i = 0; i < ce->num_interfaces; i++) {
2199 zend_string_release_ex(ce->interface_names[i].name, 0);
2200 zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2201 }
2202 efree(ce->interface_names);
2203 }
2204
2205 ce->num_interfaces = num_interfaces;
2206 ce->interfaces = interfaces;
2207 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2208
2209 for (i = 0; i < num_parent_interfaces; i++) {
2210 do_implement_interface(ce, ce->interfaces[i]);
2211 }
2212 /* Note that new interfaces can be added during this loop due to interface inheritance.
2213 * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */
2214 for (; i < num_interfaces; i++) {
2215 do_interface_implementation(ce, ce->interfaces[i]);
2216 }
2217 }
2218 /* }}} */
2219
2220
zend_inheritance_check_override(zend_class_entry * ce)2221 void zend_inheritance_check_override(zend_class_entry *ce)
2222 {
2223 zend_function *f;
2224
2225 if (ce->ce_flags & ZEND_ACC_TRAIT) {
2226 return;
2227 }
2228
2229 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, f) {
2230 if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2231 ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2232
2233 zend_error_at_noreturn(
2234 E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2235 "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2236 ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2237 }
2238 } ZEND_HASH_FOREACH_END();
2239
2240 if (ce->num_hooked_props) {
2241 zend_property_info *prop;
2242 ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
2243 if (!prop->hooks) {
2244 continue;
2245 }
2246 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2247 f = prop->hooks[i];
2248 if (f && f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2249 ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2250
2251 zend_error_at_noreturn(
2252 E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2253 "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2254 ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2255 }
2256 }
2257 } ZEND_HASH_FOREACH_END();
2258 }
2259 }
2260
2261
fixup_trait_scope(const zend_function * fn,zend_class_entry * ce)2262 static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
2263 {
2264 /* self in trait methods should be resolved to the using class, not the trait. */
2265 return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
2266 }
2267
zend_add_trait_method(zend_class_entry * ce,zend_string * name,zend_string * key,zend_function * fn)2268 static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
2269 {
2270 zend_function *existing_fn = NULL;
2271 zend_function *new_fn;
2272 bool check_inheritance = false;
2273
2274 if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
2275 /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
2276 * of where it is coming from there is no conflict and we do not need to add it again */
2277 if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
2278 (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
2279 (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
2280 return;
2281 }
2282
2283 /* Abstract method signatures from the trait must be satisfied. */
2284 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2285 /* "abstract private" methods in traits were not available prior to PHP 8.
2286 * As such, "abstract protected" was sometimes used to indicate trait requirements,
2287 * even though the "implementing" method was private. Do not check visibility
2288 * requirements to maintain backwards-compatibility with such usage.
2289 */
2290 do_inheritance_check_on_method(
2291 existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
2292 ce, NULL, ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
2293 return;
2294 }
2295
2296 if (existing_fn->common.scope == ce) {
2297 /* members from the current class override trait methods */
2298 return;
2299 } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
2300 && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
2301 /* two traits can't define the same non-abstract method */
2302 zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
2303 ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
2304 ZSTR_VAL(ce->name), ZSTR_VAL(name),
2305 ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
2306 } else {
2307 check_inheritance = true;
2308 }
2309 }
2310
2311 if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
2312 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
2313 memcpy(new_fn, fn, sizeof(zend_internal_function));
2314 new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
2315 } else {
2316 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2317 memcpy(new_fn, fn, sizeof(zend_op_array));
2318 new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2319 }
2320 new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2321
2322 /* Reassign method name, in case it is an alias. */
2323 new_fn->common.function_name = name;
2324 function_add_ref(new_fn);
2325 fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2326 zend_add_magic_method(ce, fn, key);
2327
2328 if (check_inheritance) {
2329 /* Inherited members are overridden by members inserted by traits.
2330 * Check whether the trait method fulfills the inheritance requirements. */
2331 uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2332 if (!(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2333 flags |= ZEND_INHERITANCE_SET_CHILD_CHANGED |ZEND_INHERITANCE_SET_CHILD_PROTO |
2334 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2335 }
2336 do_inheritance_check_on_method(
2337 fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce),
2338 ce, NULL, flags);
2339 }
2340 }
2341 /* }}} */
2342
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce)2343 static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2344 {
2345 if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
2346
2347 fn->common.scope = ce;
2348
2349 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2350 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2351 }
2352 if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2353 ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2354 }
2355 }
2356 }
2357 /* }}} */
2358
zend_traits_check_private_final_inheritance(uint32_t original_fn_flags,zend_function * fn_copy,zend_string * name)2359 static void zend_traits_check_private_final_inheritance(uint32_t original_fn_flags, zend_function *fn_copy, zend_string *name)
2360 {
2361 /* If the function was originally already private+final, then it will have already been warned about.
2362 * If the function became private+final only after applying modifiers, we need to emit the same warning. */
2363 if ((original_fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) != (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2364 && (fn_copy->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2365 && !zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2366 zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2367 }
2368 }
2369
zend_traits_copy_functions(zend_string * fnname,zend_function * fn,zend_class_entry * ce,HashTable * exclude_table,zend_class_entry ** aliases)2370 static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
2371 {
2372 zend_trait_alias *alias, **alias_ptr;
2373 zend_string *lcname;
2374 zend_function fn_copy;
2375 int i;
2376
2377 /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2378 if (ce->trait_aliases) {
2379 alias_ptr = ce->trait_aliases;
2380 alias = *alias_ptr;
2381 i = 0;
2382 while (alias) {
2383 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2384 if (alias->alias != NULL
2385 && fn->common.scope == aliases[i]
2386 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2387 ) {
2388 fn_copy = *fn;
2389 if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2390 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2391 } else {
2392 fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2393 }
2394
2395 zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2396
2397 lcname = zend_string_tolower(alias->alias);
2398 zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2399 zend_string_release_ex(lcname, 0);
2400 }
2401 alias_ptr++;
2402 alias = *alias_ptr;
2403 i++;
2404 }
2405 }
2406
2407 if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2408 /* is not in hashtable, thus, function is not to be excluded */
2409 memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
2410
2411 /* apply aliases which have not alias name, just setting visibility */
2412 if (ce->trait_aliases) {
2413 alias_ptr = ce->trait_aliases;
2414 alias = *alias_ptr;
2415 i = 0;
2416 while (alias) {
2417 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2418 if (alias->alias == NULL && alias->modifiers != 0
2419 && fn->common.scope == aliases[i]
2420 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2421 ) {
2422 if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2423 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2424 } else {
2425 fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2426 }
2427 }
2428 alias_ptr++;
2429 alias = *alias_ptr;
2430 i++;
2431 }
2432 }
2433
2434 zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2435
2436 zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2437 }
2438 }
2439 /* }}} */
2440
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait,zend_class_entry ** traits)2441 static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait, zend_class_entry **traits) /* {{{ */
2442 {
2443 uint32_t i;
2444
2445 if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2446 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));
2447 return 0;
2448 }
2449
2450 for (i = 0; i < ce->num_traits; i++) {
2451 if (traits[i] == trait) {
2452 return i;
2453 }
2454 }
2455 zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
2456 return 0;
2457 }
2458 /* }}} */
2459
zend_traits_init_trait_structures(zend_class_entry * ce,zend_class_entry ** traits,HashTable *** exclude_tables_ptr,zend_class_entry *** aliases_ptr)2460 static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
2461 {
2462 size_t i, j = 0;
2463 zend_trait_precedence **precedences;
2464 zend_trait_precedence *cur_precedence;
2465 zend_trait_method_reference *cur_method_ref;
2466 zend_string *lc_trait_name;
2467 zend_string *lcname;
2468 HashTable **exclude_tables = NULL;
2469 zend_class_entry **aliases = NULL;
2470 zend_class_entry *trait;
2471
2472 /* resolve class references */
2473 if (ce->trait_precedences) {
2474 exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2475 i = 0;
2476 precedences = ce->trait_precedences;
2477 ce->trait_precedences = NULL;
2478 while ((cur_precedence = precedences[i])) {
2479 /** Resolve classes for all precedence operations. */
2480 cur_method_ref = &cur_precedence->trait_method;
2481 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2482 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2483 zend_string_release_ex(lc_trait_name, 0);
2484 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2485 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2486 }
2487 zend_check_trait_usage(ce, trait, traits);
2488
2489 /** Ensure that the preferred method is actually available. */
2490 lcname = zend_string_tolower(cur_method_ref->method_name);
2491 if (!zend_hash_exists(&trait->function_table, lcname)) {
2492 zend_error_noreturn(E_COMPILE_ERROR,
2493 "A precedence rule was defined for %s::%s but this method does not exist",
2494 ZSTR_VAL(trait->name),
2495 ZSTR_VAL(cur_method_ref->method_name));
2496 }
2497
2498 /** With the other traits, we are more permissive.
2499 We do not give errors for those. This allows to be more
2500 defensive in such definitions.
2501 However, we want to make sure that the insteadof declaration
2502 is consistent in itself.
2503 */
2504
2505 for (j = 0; j < cur_precedence->num_excludes; j++) {
2506 zend_string* class_name = cur_precedence->exclude_class_names[j];
2507 zend_class_entry *exclude_ce;
2508 uint32_t trait_num;
2509
2510 lc_trait_name = zend_string_tolower(class_name);
2511 exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2512 zend_string_release_ex(lc_trait_name, 0);
2513 if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2514 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2515 }
2516 trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2517 if (!exclude_tables[trait_num]) {
2518 ALLOC_HASHTABLE(exclude_tables[trait_num]);
2519 zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2520 }
2521 if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2522 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));
2523 }
2524
2525 /* make sure that the trait method is not from a class mentioned in
2526 exclude_from_classes, for consistency */
2527 if (trait == exclude_ce) {
2528 zend_error_noreturn(E_COMPILE_ERROR,
2529 "Inconsistent insteadof definition. "
2530 "The method %s is to be used from %s, but %s is also on the exclude list",
2531 ZSTR_VAL(cur_method_ref->method_name),
2532 ZSTR_VAL(trait->name),
2533 ZSTR_VAL(trait->name));
2534 }
2535 }
2536 zend_string_release_ex(lcname, 0);
2537 i++;
2538 }
2539 ce->trait_precedences = precedences;
2540 }
2541
2542 if (ce->trait_aliases) {
2543 i = 0;
2544 while (ce->trait_aliases[i]) {
2545 i++;
2546 }
2547 aliases = ecalloc(i, sizeof(zend_class_entry*));
2548 i = 0;
2549 while (ce->trait_aliases[i]) {
2550 zend_trait_alias *cur_alias = ce->trait_aliases[i];
2551 cur_method_ref = &ce->trait_aliases[i]->trait_method;
2552 lcname = zend_string_tolower(cur_method_ref->method_name);
2553 if (cur_method_ref->class_name) {
2554 /* For all aliases with an explicit class name, resolve the class now. */
2555 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2556 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2557 zend_string_release_ex(lc_trait_name, 0);
2558 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2559 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2560 }
2561 zend_check_trait_usage(ce, trait, traits);
2562 aliases[i] = trait;
2563
2564 /* And, ensure that the referenced method is resolvable, too. */
2565 if (!zend_hash_exists(&trait->function_table, lcname)) {
2566 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));
2567 }
2568 } else {
2569 /* Find out which trait this method refers to. */
2570 trait = NULL;
2571 for (j = 0; j < ce->num_traits; j++) {
2572 if (traits[j]) {
2573 if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2574 if (!trait) {
2575 trait = traits[j];
2576 continue;
2577 }
2578
2579 zend_error_noreturn(E_COMPILE_ERROR,
2580 "An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
2581 ZSTR_VAL(cur_method_ref->method_name),
2582 ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2583 ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2584 ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2585 }
2586 }
2587 }
2588
2589 /* Non-absolute method reference refers to method that does not exist. */
2590 if (!trait) {
2591 if (cur_alias->alias) {
2592 zend_error_noreturn(E_COMPILE_ERROR,
2593 "An alias (%s) was defined for method %s(), but this method does not exist",
2594 ZSTR_VAL(cur_alias->alias),
2595 ZSTR_VAL(cur_alias->trait_method.method_name));
2596 } else {
2597 zend_error_noreturn(E_COMPILE_ERROR,
2598 "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2599 ZSTR_VAL(cur_alias->trait_method.method_name));
2600 }
2601 }
2602
2603 aliases[i] = trait;
2604 }
2605 zend_string_release_ex(lcname, 0);
2606 i++;
2607 }
2608 }
2609
2610 *exclude_tables_ptr = exclude_tables;
2611 *aliases_ptr = aliases;
2612 }
2613 /* }}} */
2614
zend_do_traits_method_binding(zend_class_entry * ce,zend_class_entry ** traits,HashTable ** exclude_tables,zend_class_entry ** aliases)2615 static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
2616 {
2617 uint32_t i;
2618 zend_string *key;
2619 zend_function *fn;
2620
2621 if (exclude_tables) {
2622 for (i = 0; i < ce->num_traits; i++) {
2623 if (traits[i]) {
2624 /* copies functions, applies defined aliasing, and excludes unused trait methods */
2625 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2626 zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2627 } ZEND_HASH_FOREACH_END();
2628
2629 if (exclude_tables[i]) {
2630 zend_hash_destroy(exclude_tables[i]);
2631 FREE_HASHTABLE(exclude_tables[i]);
2632 exclude_tables[i] = NULL;
2633 }
2634 }
2635 }
2636 } else {
2637 for (i = 0; i < ce->num_traits; i++) {
2638 if (traits[i]) {
2639 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2640 zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2641 } ZEND_HASH_FOREACH_END();
2642 }
2643 }
2644 }
2645
2646 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
2647 zend_fixup_trait_method(fn, ce);
2648 } ZEND_HASH_FOREACH_END();
2649 }
2650 /* }}} */
2651
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)2652 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) /* {{{ */
2653 {
2654 /* This function is used to show the place of the existing conflicting
2655 * definition in error messages when conflicts occur. Since trait constants
2656 * are flattened into the constants table of the composing class, and thus
2657 * we lose information about which constant was defined in which trait, a
2658 * process like this is needed to find the location of the first definition
2659 * of the constant from traits.
2660 */
2661 size_t i;
2662
2663 if (colliding_ce == ce) {
2664 for (i = 0; i < current_trait; i++) {
2665 if (traits[i]
2666 && zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2667 return traits[i];
2668 }
2669 }
2670 }
2671 /* Traits don't have it, then the composing class (or trait) itself has it. */
2672 return colliding_ce;
2673 }
2674 /* }}} */
2675
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)2676 static void emit_incompatible_trait_constant_error(
2677 const zend_class_entry *ce, const zend_class_constant *existing_constant, const zend_class_constant *trait_constant, zend_string *name,
2678 zend_class_entry **traits, size_t current_trait
2679 ) {
2680 zend_error_noreturn(E_COMPILE_ERROR,
2681 "%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2682 ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2683 ZSTR_VAL(trait_constant->ce->name),
2684 ZSTR_VAL(name),
2685 ZSTR_VAL(ce->name)
2686 );
2687 }
2688
do_trait_constant_check(zend_class_entry * ce,zend_class_constant * trait_constant,zend_string * name,zend_class_entry ** traits,size_t current_trait)2689 static bool do_trait_constant_check(
2690 zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait
2691 ) {
2692 uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2693
2694 zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2695 if (zv == NULL) {
2696 /* No existing constant of the same name, so this one can be added */
2697 return true;
2698 }
2699
2700 zend_class_constant *existing_constant = Z_PTR_P(zv);
2701
2702 if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2703 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2704 return false;
2705 }
2706
2707 if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) {
2708 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2709 return false;
2710 } else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2711 inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2712 inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2713 if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
2714 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2715 return false;
2716 }
2717 }
2718
2719 if (!check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &existing_constant->value)) {
2720 /* There is an existing constant of the same name, and it conflicts with the new one, so let's throw a fatal error */
2721 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2722 return false;
2723 }
2724
2725 /* There is an existing constant which is compatible with the new one, so no need to add it */
2726 return false;
2727 }
2728
zend_do_traits_constant_binding(zend_class_entry * ce,zend_class_entry ** traits)2729 static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2730 {
2731 size_t i;
2732
2733 for (i = 0; i < ce->num_traits; i++) {
2734 zend_string *constant_name;
2735 zend_class_constant *constant;
2736
2737 if (!traits[i]) {
2738 continue;
2739 }
2740
2741 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2742 if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2743 zend_class_constant *ct = NULL;
2744
2745 ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2746 memcpy(ct, constant, sizeof(zend_class_constant));
2747 constant = ct;
2748
2749 if (Z_TYPE(constant->value) == IS_CONSTANT_AST) {
2750 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2751 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2752 }
2753
2754 /* Unlike interface implementations and class inheritances,
2755 * access control of the trait constants is done by the scope
2756 * of the composing class. So let's replace the ce here.
2757 */
2758 constant->ce = ce;
2759
2760 Z_TRY_ADDREF(constant->value);
2761 constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2762 if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2763 GC_ADDREF(constant->attributes);
2764 }
2765
2766 zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2767 }
2768 } ZEND_HASH_FOREACH_END();
2769 }
2770 }
2771 /* }}} */
2772
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)2773 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) /* {{{ */
2774 {
2775 size_t i;
2776
2777 if (colliding_ce == ce) {
2778 for (i = 0; i < current_trait; i++) {
2779 if (traits[i]
2780 && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2781 return traits[i];
2782 }
2783 }
2784 }
2785
2786 return colliding_ce;
2787 }
2788 /* }}} */
2789
zend_do_traits_property_binding(zend_class_entry * ce,zend_class_entry ** traits)2790 static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2791 {
2792 size_t i;
2793 zend_property_info *property_info;
2794 const zend_property_info *colliding_prop;
2795 zend_property_info *new_prop;
2796 zend_string* prop_name;
2797 zval* prop_value;
2798 zend_string *doc_comment;
2799
2800 /* In the following steps the properties are inserted into the property table
2801 * for that, a very strict approach is applied:
2802 * - check for compatibility, if not compatible with any property in class -> fatal
2803 * - if compatible, then strict notice
2804 */
2805 for (i = 0; i < ce->num_traits; i++) {
2806 if (!traits[i]) {
2807 continue;
2808 }
2809 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2810 uint32_t flags = property_info->flags;
2811
2812 /* next: check for conflicts with current class */
2813 if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2814 if ((colliding_prop->flags & ZEND_ACC_PRIVATE) && colliding_prop->ce != ce) {
2815 zend_hash_del(&ce->properties_info, prop_name);
2816 flags |= ZEND_ACC_CHANGED;
2817 } else {
2818 bool is_compatible = false;
2819 uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2820
2821 if (colliding_prop->hooks || property_info->hooks) {
2822 zend_error_noreturn(E_COMPILE_ERROR,
2823 "%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",
2824 ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2825 ZSTR_VAL(property_info->ce->name),
2826 ZSTR_VAL(prop_name),
2827 ZSTR_VAL(ce->name));
2828 }
2829
2830 if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2831 verify_property_type_compatibility(property_info, colliding_prop, PROP_INVARIANT, false, false) == INHERITANCE_SUCCESS
2832 ) {
2833 /* the flags are identical, thus, the properties may be compatible */
2834 zval *op1, *op2;
2835
2836 if (flags & ZEND_ACC_STATIC) {
2837 op1 = &ce->default_static_members_table[colliding_prop->offset];
2838 op2 = &traits[i]->default_static_members_table[property_info->offset];
2839 ZVAL_DEINDIRECT(op1);
2840 ZVAL_DEINDIRECT(op2);
2841 } else {
2842 op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2843 op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2844 }
2845 is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2846 }
2847
2848 if (!is_compatible) {
2849 zend_error_noreturn(E_COMPILE_ERROR,
2850 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2851 ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2852 ZSTR_VAL(property_info->ce->name),
2853 ZSTR_VAL(prop_name),
2854 ZSTR_VAL(ce->name));
2855 }
2856 if (!(flags & ZEND_ACC_STATIC)) {
2857 continue;
2858 }
2859 }
2860 }
2861
2862 if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS) && !(property_info->flags & ZEND_ACC_READONLY)) {
2863 zend_error_noreturn(E_COMPILE_ERROR,
2864 "Readonly class %s cannot use trait with a non-readonly property %s::$%s",
2865 ZSTR_VAL(ce->name),
2866 ZSTR_VAL(property_info->ce->name),
2867 ZSTR_VAL(prop_name)
2868 );
2869 }
2870
2871 /* property not found, so lets add it */
2872 zval tmp_prop_value;
2873 if (!(flags & ZEND_ACC_VIRTUAL)) {
2874 if (flags & ZEND_ACC_STATIC) {
2875 prop_value = &traits[i]->default_static_members_table[property_info->offset];
2876 ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2877 } else {
2878 prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2879 }
2880 Z_TRY_ADDREF_P(prop_value);
2881 } else {
2882 prop_value = &tmp_prop_value;
2883 ZVAL_UNDEF(&tmp_prop_value);
2884 }
2885 doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2886
2887 zend_type type = property_info->type;
2888 /* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2889 zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2890 new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2891
2892 if (property_info->attributes) {
2893 new_prop->attributes = property_info->attributes;
2894
2895 if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2896 GC_ADDREF(new_prop->attributes);
2897 }
2898 }
2899 if (property_info->hooks) {
2900 zend_function **hooks = new_prop->hooks =
2901 zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2902 memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2903 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2904 if (hooks[i]) {
2905 zend_function *old_fn = hooks[i];
2906
2907 /* Hooks are not yet supported for internal properties. */
2908 ZEND_ASSERT(ZEND_USER_CODE(old_fn->type));
2909
2910 /* Copy the function, because we need to adjust the scope. */
2911 zend_function *new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2912 memcpy(new_fn, old_fn, sizeof(zend_op_array));
2913 new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2914 new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2915 new_fn->common.prop_info = new_prop;
2916 function_add_ref(new_fn);
2917
2918 zend_fixup_trait_method(new_fn, ce);
2919
2920 hooks[i] = new_fn;
2921 }
2922 }
2923 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2924 }
2925 } ZEND_HASH_FOREACH_END();
2926 }
2927 }
2928 /* }}} */
2929
zend_do_bind_traits(zend_class_entry * ce,zend_class_entry ** traits)2930 static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2931 {
2932 HashTable **exclude_tables;
2933 zend_class_entry **aliases;
2934
2935 ZEND_ASSERT(ce->num_traits > 0);
2936
2937 /* complete initialization of trait structures in ce */
2938 zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases);
2939
2940 /* first care about all methods to be flattened into the class */
2941 zend_do_traits_method_binding(ce, traits, exclude_tables, aliases);
2942
2943 if (aliases) {
2944 efree(aliases);
2945 }
2946
2947 if (exclude_tables) {
2948 efree(exclude_tables);
2949 }
2950
2951 /* then flatten the constants and properties into it, to, mostly to notify developer about problems */
2952 zend_do_traits_constant_binding(ce, traits);
2953 zend_do_traits_property_binding(ce, traits);
2954 }
2955 /* }}} */
2956
2957 #define MAX_ABSTRACT_INFO_CNT 3
2958 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
2959 #define DISPLAY_ABSTRACT_FN(idx) \
2960 ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
2961 ai.afn[idx] ? "::" : "", \
2962 ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
2963 ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
2964
2965 typedef struct _zend_abstract_info {
2966 const zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
2967 int cnt;
2968 } zend_abstract_info;
2969
zend_verify_abstract_class_function(const zend_function * fn,zend_abstract_info * ai)2970 static void zend_verify_abstract_class_function(const zend_function *fn, zend_abstract_info *ai) /* {{{ */
2971 {
2972 if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
2973 ai->afn[ai->cnt] = fn;
2974 }
2975 ai->cnt++;
2976 }
2977 /* }}} */
2978
zend_verify_abstract_class(zend_class_entry * ce)2979 void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
2980 {
2981 const zend_function *func;
2982 zend_abstract_info ai;
2983 bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
2984 bool can_be_abstract = (ce->ce_flags & ZEND_ACC_ENUM) == 0;
2985 memset(&ai, 0, sizeof(ai));
2986
2987 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
2988 if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
2989 /* If the class is explicitly abstract, we only check private abstract methods,
2990 * because only they must be declared in the same class. */
2991 if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
2992 zend_verify_abstract_class_function(func, &ai);
2993 }
2994 }
2995 } ZEND_HASH_FOREACH_END();
2996
2997 if (!is_explicit_abstract) {
2998 const zend_property_info *prop_info;
2999 ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
3000 if (prop_info->hooks) {
3001 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3002 const zend_function *fn = prop_info->hooks[i];
3003 if (fn && (fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3004 zend_verify_abstract_class_function(fn, &ai);
3005 }
3006 }
3007 }
3008 } ZEND_HASH_FOREACH_END();
3009 }
3010
3011 if (ai.cnt) {
3012 zend_error_noreturn(E_ERROR, !is_explicit_abstract && can_be_abstract
3013 ? "%s %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")"
3014 : "%s %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3015 zend_get_object_type_uc(ce),
3016 ZSTR_VAL(ce->name), ai.cnt,
3017 ai.cnt > 1 ? "s" : "",
3018 DISPLAY_ABSTRACT_FN(0),
3019 DISPLAY_ABSTRACT_FN(1),
3020 DISPLAY_ABSTRACT_FN(2)
3021 );
3022 } else {
3023 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
3024 ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3025 }
3026 }
3027 /* }}} */
3028
3029 typedef struct {
3030 enum {
3031 OBLIGATION_DEPENDENCY,
3032 OBLIGATION_COMPATIBILITY,
3033 OBLIGATION_PROPERTY_COMPATIBILITY,
3034 OBLIGATION_CLASS_CONSTANT_COMPATIBILITY,
3035 OBLIGATION_PROPERTY_HOOK,
3036 } type;
3037 union {
3038 zend_class_entry *dependency_ce;
3039 struct {
3040 /* Traits may use temporary on-stack functions during inheritance checks,
3041 * so use copies of functions here as well. */
3042 zend_function parent_fn;
3043 zend_function child_fn;
3044 zend_class_entry *child_scope;
3045 zend_class_entry *parent_scope;
3046 };
3047 struct {
3048 const zend_property_info *parent_prop;
3049 const zend_property_info *child_prop;
3050 prop_variance variance;
3051 };
3052 struct {
3053 const zend_string *const_name;
3054 const zend_class_constant *parent_const;
3055 const zend_class_constant *child_const;
3056 };
3057 struct {
3058 const zend_property_info *hooked_prop;
3059 const zend_function *hook_func;
3060 };
3061 };
3062 } variance_obligation;
3063
variance_obligation_dtor(zval * zv)3064 static void variance_obligation_dtor(zval *zv) {
3065 efree(Z_PTR_P(zv));
3066 }
3067
variance_obligation_ht_dtor(zval * zv)3068 static void variance_obligation_ht_dtor(zval *zv) {
3069 zend_hash_destroy(Z_PTR_P(zv));
3070 FREE_HASHTABLE(Z_PTR_P(zv));
3071 }
3072
get_or_init_obligations_for_class(zend_class_entry * ce)3073 static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
3074 HashTable *ht;
3075 zend_ulong key;
3076 if (!CG(delayed_variance_obligations)) {
3077 ALLOC_HASHTABLE(CG(delayed_variance_obligations));
3078 zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
3079 }
3080
3081 key = (zend_ulong) (uintptr_t) ce;
3082 ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
3083 if (ht) {
3084 return ht;
3085 }
3086
3087 ALLOC_HASHTABLE(ht);
3088 zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
3089 zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
3090 ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
3091 return ht;
3092 }
3093
add_dependency_obligation(zend_class_entry * ce,zend_class_entry * dependency_ce)3094 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
3095 HashTable *obligations = get_or_init_obligations_for_class(ce);
3096 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3097 obligation->type = OBLIGATION_DEPENDENCY;
3098 obligation->dependency_ce = dependency_ce;
3099 zend_hash_next_index_insert_ptr(obligations, obligation);
3100 }
3101
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)3102 static void add_compatibility_obligation(
3103 zend_class_entry *ce,
3104 const zend_function *child_fn, zend_class_entry *child_scope,
3105 const zend_function *parent_fn, zend_class_entry *parent_scope) {
3106 HashTable *obligations = get_or_init_obligations_for_class(ce);
3107 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3108 obligation->type = OBLIGATION_COMPATIBILITY;
3109 /* Copy functions, because they may be stack-allocated in the case of traits. */
3110 if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3111 memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
3112 } else {
3113 memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
3114 }
3115 if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3116 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
3117 } else {
3118 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
3119 }
3120 obligation->child_scope = child_scope;
3121 obligation->parent_scope = parent_scope;
3122 zend_hash_next_index_insert_ptr(obligations, obligation);
3123 }
3124
add_property_compatibility_obligation(zend_class_entry * ce,const zend_property_info * child_prop,const zend_property_info * parent_prop,prop_variance variance)3125 static void add_property_compatibility_obligation(
3126 zend_class_entry *ce, const zend_property_info *child_prop,
3127 const zend_property_info *parent_prop, prop_variance variance) {
3128 HashTable *obligations = get_or_init_obligations_for_class(ce);
3129 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3130 obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
3131 obligation->child_prop = child_prop;
3132 obligation->parent_prop = parent_prop;
3133 obligation->variance = variance;
3134 zend_hash_next_index_insert_ptr(obligations, obligation);
3135 }
3136
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)3137 static void add_class_constant_compatibility_obligation(
3138 zend_class_entry *ce, const zend_class_constant *child_const,
3139 const zend_class_constant *parent_const, const zend_string *const_name) {
3140 HashTable *obligations = get_or_init_obligations_for_class(ce);
3141 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3142 obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY;
3143 obligation->const_name = const_name;
3144 obligation->child_const = child_const;
3145 obligation->parent_const = parent_const;
3146 zend_hash_next_index_insert_ptr(obligations, obligation);
3147 }
3148
add_property_hook_obligation(zend_class_entry * ce,const zend_property_info * hooked_prop,const zend_function * hook_func)3149 static void add_property_hook_obligation(
3150 zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func) {
3151 HashTable *obligations = get_or_init_obligations_for_class(ce);
3152 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3153 obligation->type = OBLIGATION_PROPERTY_HOOK;
3154 obligation->hooked_prop = hooked_prop;
3155 obligation->hook_func = hook_func;
3156 zend_hash_next_index_insert_ptr(obligations, obligation);
3157 }
3158
3159 static void resolve_delayed_variance_obligations(zend_class_entry *ce);
3160
check_variance_obligation(variance_obligation * obligation)3161 static void check_variance_obligation(variance_obligation *obligation) {
3162 if (obligation->type == OBLIGATION_DEPENDENCY) {
3163 zend_class_entry *dependency_ce = obligation->dependency_ce;
3164 if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3165 zend_class_entry *orig_linking_class = CG(current_linking_class);
3166
3167 CG(current_linking_class) =
3168 (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
3169 resolve_delayed_variance_obligations(dependency_ce);
3170 CG(current_linking_class) = orig_linking_class;
3171 }
3172 } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
3173 inheritance_status status = zend_do_perform_implementation_check(
3174 &obligation->child_fn, obligation->child_scope,
3175 &obligation->parent_fn, obligation->parent_scope);
3176 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3177 emit_incompatible_method_error(
3178 &obligation->child_fn, obligation->child_scope,
3179 &obligation->parent_fn, obligation->parent_scope, status);
3180 }
3181 /* Either the compatibility check was successful or only threw a warning. */
3182 } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
3183 verify_property_type_compatibility(obligation->parent_prop, obligation->child_prop, obligation->variance, true, true);
3184 } else if (obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY) {
3185 inheritance_status status =
3186 class_constant_types_compatible(obligation->parent_const, obligation->child_const);
3187 if (status != INHERITANCE_SUCCESS) {
3188 emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name);
3189 }
3190 } else if (obligation->type == OBLIGATION_PROPERTY_HOOK) {
3191 inheritance_status status = zend_verify_property_hook_variance(obligation->hooked_prop, obligation->hook_func);
3192 if (status != INHERITANCE_SUCCESS) {
3193 zend_hooked_property_variance_error(obligation->hooked_prop);
3194 }
3195 } else {
3196 ZEND_UNREACHABLE();
3197 }
3198 }
3199
load_delayed_classes(zend_class_entry * ce)3200 static void load_delayed_classes(zend_class_entry *ce) {
3201 HashTable *delayed_autoloads = CG(delayed_autoloads);
3202 if (!delayed_autoloads) {
3203 return;
3204 }
3205
3206 /* Autoloading can trigger linking of another class, which may register new delayed autoloads.
3207 * For that reason, this code uses a loop that pops and loads the first element of the HT. If
3208 * this triggers linking, then the remaining classes may get loaded when linking the newly
3209 * loaded class. This is important, as otherwise necessary dependencies may not be available
3210 * if the new class is lower in the hierarchy than the current one. */
3211 HashPosition pos = 0;
3212 zend_string *name;
3213 zend_ulong idx;
3214 while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
3215 != HASH_KEY_NON_EXISTENT) {
3216 zend_string_addref(name);
3217 zend_hash_del(delayed_autoloads, name);
3218 zend_lookup_class(name);
3219 zend_string_release(name);
3220 if (EG(exception)) {
3221 zend_exception_uncaught_error(
3222 "During inheritance of %s, while autoloading %s",
3223 ZSTR_VAL(ce->name), ZSTR_VAL(name));
3224 }
3225 }
3226 }
3227
resolve_delayed_variance_obligations(zend_class_entry * ce)3228 static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
3229 HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
3230 zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
3231
3232 ZEND_ASSERT(all_obligations != NULL);
3233 obligations = zend_hash_index_find_ptr(all_obligations, num_key);
3234 ZEND_ASSERT(obligations != NULL);
3235
3236 variance_obligation *obligation;
3237 ZEND_HASH_FOREACH_PTR(obligations, obligation) {
3238 check_variance_obligation(obligation);
3239 } ZEND_HASH_FOREACH_END();
3240
3241 zend_inheritance_check_override(ce);
3242
3243 ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
3244 ce->ce_flags |= ZEND_ACC_LINKED;
3245 zend_hash_index_del(all_obligations, num_key);
3246 }
3247
check_unrecoverable_load_failure(const zend_class_entry * ce)3248 static void check_unrecoverable_load_failure(const zend_class_entry *ce) {
3249 /* If this class has been used while unlinked through a variance obligation, it is not legal
3250 * to remove the class from the class table and throw an exception, because there is already
3251 * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
3252 * a fatal error, as would happen if we did not allow exceptions in the first place. */
3253 if (CG(unlinked_uses)
3254 && zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t)ce) == SUCCESS) {
3255 zend_exception_uncaught_error(
3256 "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
3257 }
3258 }
3259
3260 #define zend_update_inherited_handler(handler) do { \
3261 if (ce->handler == (zend_function*)op_array) { \
3262 ce->handler = (zend_function*)new_op_array; \
3263 } \
3264 } while (0)
3265
zend_lazy_method_load(zend_op_array * op_array,zend_class_entry * ce,const zend_class_entry * pce)3266 static zend_op_array *zend_lazy_method_load(
3267 zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3268 ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3269 ZEND_ASSERT(op_array->scope == pce);
3270 ZEND_ASSERT(op_array->prototype == NULL);
3271 zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3272 memcpy(new_op_array, op_array, sizeof(zend_op_array));
3273 new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3274 new_op_array->scope = ce;
3275 ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3276 ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3277
3278 return new_op_array;
3279 }
3280
zend_lazy_class_load(zend_class_entry * pce)3281 static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
3282 {
3283 zend_class_entry *ce;
3284 Bucket *p, *end;
3285
3286 ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3287 memcpy(ce, pce, sizeof(zend_class_entry));
3288 ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3289 ce->refcount = 1;
3290 ce->inheritance_cache = NULL;
3291 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3292 ZEND_MAP_PTR_NEW(ce->mutable_data);
3293 } else {
3294 ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3295 }
3296
3297 /* properties */
3298 if (ce->default_properties_table) {
3299 zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3300 zval *src = ce->default_properties_table;
3301 zval *end = src + ce->default_properties_count;
3302
3303 ce->default_properties_table = dst;
3304 for (; src != end; src++, dst++) {
3305 ZVAL_COPY_VALUE_PROP(dst, src);
3306 }
3307 }
3308
3309 /* methods */
3310 ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3311 if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3312 p = emalloc(HT_SIZE(&ce->function_table));
3313 memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3314 HT_SET_DATA_ADDR(&ce->function_table, p);
3315 p = ce->function_table.arData;
3316 end = p + ce->function_table.nNumUsed;
3317 for (; p != end; p++) {
3318 zend_op_array *op_array = Z_PTR(p->val);
3319 zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3320
3321 zend_update_inherited_handler(constructor);
3322 zend_update_inherited_handler(destructor);
3323 zend_update_inherited_handler(clone);
3324 zend_update_inherited_handler(__get);
3325 zend_update_inherited_handler(__set);
3326 zend_update_inherited_handler(__call);
3327 zend_update_inherited_handler(__isset);
3328 zend_update_inherited_handler(__unset);
3329 zend_update_inherited_handler(__tostring);
3330 zend_update_inherited_handler(__callstatic);
3331 zend_update_inherited_handler(__debugInfo);
3332 zend_update_inherited_handler(__serialize);
3333 zend_update_inherited_handler(__unserialize);
3334 }
3335 }
3336
3337 /* static members */
3338 if (ce->default_static_members_table) {
3339 zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
3340 zval *src = ce->default_static_members_table;
3341 zval *end = src + ce->default_static_members_count;
3342
3343 ce->default_static_members_table = dst;
3344 for (; src != end; src++, dst++) {
3345 ZVAL_COPY_VALUE(dst, src);
3346 }
3347 }
3348 ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3349
3350 /* properties_info */
3351 if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3352 p = emalloc(HT_SIZE(&ce->properties_info));
3353 memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3354 HT_SET_DATA_ADDR(&ce->properties_info, p);
3355 p = ce->properties_info.arData;
3356 end = p + ce->properties_info.nNumUsed;
3357 for (; p != end; p++) {
3358 zend_property_info *prop_info, *new_prop_info;
3359
3360 prop_info = Z_PTR(p->val);
3361 ZEND_ASSERT(prop_info->ce == pce);
3362 ZEND_ASSERT(prop_info->prototype == prop_info);
3363 new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3364 Z_PTR(p->val) = new_prop_info;
3365 memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3366 new_prop_info->ce = ce;
3367 new_prop_info->prototype = new_prop_info;
3368 /* Deep copy the type information */
3369 zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3370 if (new_prop_info->hooks) {
3371 new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3372 memcpy(new_prop_info->hooks, prop_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3373 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3374 if (new_prop_info->hooks[i]) {
3375 zend_op_array *hook = zend_lazy_method_load((zend_op_array *) new_prop_info->hooks[i], ce, pce);
3376 ZEND_ASSERT(hook->prop_info == prop_info);
3377 hook->prop_info = new_prop_info;
3378 new_prop_info->ce = ce;
3379 new_prop_info->hooks[i] = (zend_function *) hook;
3380 }
3381 }
3382 }
3383 }
3384 }
3385
3386 /* constants table */
3387 if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3388 p = emalloc(HT_SIZE(&ce->constants_table));
3389 memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3390 HT_SET_DATA_ADDR(&ce->constants_table, p);
3391 p = ce->constants_table.arData;
3392 end = p + ce->constants_table.nNumUsed;
3393 for (; p != end; p++) {
3394 zend_class_constant *c, *new_c;
3395
3396 c = Z_PTR(p->val);
3397 ZEND_ASSERT(c->ce == pce);
3398 new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3399 Z_PTR(p->val) = new_c;
3400 memcpy(new_c, c, sizeof(zend_class_constant));
3401 new_c->ce = ce;
3402 }
3403 }
3404
3405 return ce;
3406 }
3407
3408 #ifndef ZEND_WIN32
3409 # define UPDATE_IS_CACHEABLE(ce) do { \
3410 if ((ce)->type == ZEND_USER_CLASS) { \
3411 is_cacheable &= (ce)->ce_flags; \
3412 } \
3413 } while (0)
3414 #else
3415 // TODO: ASLR may cause different addresses in different workers ???
3416 # define UPDATE_IS_CACHEABLE(ce) do { \
3417 is_cacheable &= (ce)->ce_flags; \
3418 } while (0)
3419 #endif
3420
zend_do_link_class(zend_class_entry * ce,zend_string * lc_parent_name,zend_string * key)3421 ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key) /* {{{ */
3422 {
3423 /* Load parent/interface dependencies first, so we can still gracefully abort linking
3424 * with an exception and remove the class from the class table. This is only possible
3425 * if no variance obligations on the current class have been added during autoloading. */
3426 zend_class_entry *parent = NULL;
3427 zend_class_entry **traits_and_interfaces = NULL;
3428 zend_class_entry *proto = NULL;
3429 zend_class_entry *orig_linking_class;
3430 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3431 uint32_t i, j;
3432 zval *zv;
3433 ALLOCA_FLAG(use_heap)
3434
3435 SET_ALLOCA_FLAG(use_heap);
3436 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3437
3438 if (ce->parent_name) {
3439 parent = zend_fetch_class_by_name(
3440 ce->parent_name, lc_parent_name,
3441 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3442 if (!parent) {
3443 check_unrecoverable_load_failure(ce);
3444 return NULL;
3445 }
3446 UPDATE_IS_CACHEABLE(parent);
3447 }
3448
3449 if (ce->num_traits || ce->num_interfaces) {
3450 traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3451
3452 for (i = 0; i < ce->num_traits; i++) {
3453 zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3454 ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
3455 if (UNEXPECTED(trait == NULL)) {
3456 free_alloca(traits_and_interfaces, use_heap);
3457 return NULL;
3458 }
3459 if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
3460 zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
3461 free_alloca(traits_and_interfaces, use_heap);
3462 return NULL;
3463 }
3464 for (j = 0; j < i; j++) {
3465 if (traits_and_interfaces[j] == trait) {
3466 /* skip duplications */
3467 trait = NULL;
3468 break;
3469 }
3470 }
3471 traits_and_interfaces[i] = trait;
3472 if (trait) {
3473 UPDATE_IS_CACHEABLE(trait);
3474 }
3475 }
3476 }
3477
3478 if (ce->num_interfaces) {
3479 for (i = 0; i < ce->num_interfaces; i++) {
3480 zend_class_entry *iface = zend_fetch_class_by_name(
3481 ce->interface_names[i].name, ce->interface_names[i].lc_name,
3482 ZEND_FETCH_CLASS_INTERFACE |
3483 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3484 if (!iface) {
3485 check_unrecoverable_load_failure(ce);
3486 free_alloca(traits_and_interfaces, use_heap);
3487 return NULL;
3488 }
3489 traits_and_interfaces[ce->num_traits + i] = iface;
3490 if (iface) {
3491 UPDATE_IS_CACHEABLE(iface);
3492 }
3493 }
3494 }
3495
3496 #ifndef ZEND_WIN32
3497 if (ce->ce_flags & ZEND_ACC_ENUM) {
3498 /* We will add internal methods. */
3499 is_cacheable = false;
3500 }
3501 #endif
3502
3503 bool orig_record_errors = EG(record_errors);
3504
3505 if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3506 if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3507 zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3508 if (ret) {
3509 if (traits_and_interfaces) {
3510 free_alloca(traits_and_interfaces, use_heap);
3511 }
3512 zv = zend_hash_find_known_hash(CG(class_table), key);
3513 Z_CE_P(zv) = ret;
3514 return ret;
3515 }
3516
3517 /* Make sure warnings (such as deprecations) thrown during inheritance
3518 * will be recorded in the inheritance cache. */
3519 zend_begin_record_errors();
3520 } else {
3521 is_cacheable = 0;
3522 }
3523 proto = ce;
3524 }
3525
3526 zend_try {
3527 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3528 /* Lazy class loading */
3529 ce = zend_lazy_class_load(ce);
3530 zv = zend_hash_find_known_hash(CG(class_table), key);
3531 Z_CE_P(zv) = ce;
3532 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3533 /* Lazy class loading */
3534 ce = zend_lazy_class_load(ce);
3535 ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3536 zv = zend_hash_find_known_hash(CG(class_table), key);
3537 Z_CE_P(zv) = ce;
3538 }
3539
3540 if (CG(unlinked_uses)) {
3541 zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3542 }
3543
3544 orig_linking_class = CG(current_linking_class);
3545 CG(current_linking_class) = is_cacheable ? ce : NULL;
3546
3547 if (ce->ce_flags & ZEND_ACC_ENUM) {
3548 /* Only register builtin enum methods during inheritance to avoid persisting them in
3549 * opcache. */
3550 zend_enum_register_funcs(ce);
3551 }
3552
3553 if (parent) {
3554 if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3555 add_dependency_obligation(ce, parent);
3556 }
3557 zend_do_inheritance(ce, parent);
3558 }
3559 if (ce->num_traits) {
3560 zend_do_bind_traits(ce, traits_and_interfaces);
3561 }
3562 if (ce->num_interfaces) {
3563 /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3564 uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3565 zend_class_entry **interfaces = emalloc(
3566 sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3567
3568 if (num_parent_interfaces) {
3569 memcpy(interfaces, parent->interfaces,
3570 sizeof(zend_class_entry *) * num_parent_interfaces);
3571 }
3572 memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3573 sizeof(zend_class_entry *) * ce->num_interfaces);
3574
3575 zend_do_implement_interfaces(ce, interfaces);
3576 } else if (parent && parent->num_interfaces) {
3577 zend_do_inherit_interfaces(ce, parent);
3578 }
3579 if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3580 && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3581 ) {
3582 zend_verify_abstract_class(ce);
3583 }
3584 if (ce->ce_flags & ZEND_ACC_ENUM) {
3585 zend_verify_enum(ce);
3586 }
3587 if (ce->num_hooked_prop_variance_checks) {
3588 const zend_property_info *prop_info;
3589 ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
3590 if (prop_info->ce == ce && prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
3591 switch (zend_verify_property_hook_variance(prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
3592 case INHERITANCE_SUCCESS:
3593 break;
3594 case INHERITANCE_ERROR:
3595 zend_hooked_property_variance_error(prop_info);
3596 break;
3597 case INHERITANCE_UNRESOLVED:
3598 add_property_hook_obligation(ce, prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET]);
3599 break;
3600 case INHERITANCE_WARNING:
3601 ZEND_UNREACHABLE();
3602 }
3603 }
3604 } ZEND_HASH_FOREACH_END();
3605 }
3606
3607 /* Normally Stringable is added during compilation. However, if it is imported from a trait,
3608 * we need to explicitly add the interface here. */
3609 if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3610 && !zend_class_implements_interface(ce, zend_ce_stringable)) {
3611 ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
3612 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
3613 ce->num_interfaces++;
3614 ce->interfaces = perealloc(ce->interfaces,
3615 sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
3616 ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
3617 do_interface_implementation(ce, zend_ce_stringable);
3618 }
3619
3620 zend_build_properties_info_table(ce);
3621 } zend_catch {
3622 /* Do not leak recorded errors to the next linked class. */
3623 if (!orig_record_errors) {
3624 EG(record_errors) = false;
3625 zend_free_recorded_errors();
3626 }
3627 zend_bailout();
3628 } zend_end_try();
3629
3630 EG(record_errors) = orig_record_errors;
3631
3632 if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3633 zend_inheritance_check_override(ce);
3634 ce->ce_flags |= ZEND_ACC_LINKED;
3635 } else {
3636 ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
3637 if (CG(current_linking_class)) {
3638 ce->ce_flags |= ZEND_ACC_CACHEABLE;
3639 }
3640 load_delayed_classes(ce);
3641 if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3642 resolve_delayed_variance_obligations(ce);
3643 }
3644 if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3645 ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3646 } else {
3647 CG(current_linking_class) = NULL;
3648 }
3649 }
3650
3651 if (!CG(current_linking_class)) {
3652 is_cacheable = 0;
3653 }
3654 CG(current_linking_class) = orig_linking_class;
3655
3656 if (is_cacheable) {
3657 HashTable *ht = (HashTable*)ce->inheritance_cache;
3658 zend_class_entry *new_ce;
3659
3660 ce->inheritance_cache = NULL;
3661 new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3662 if (new_ce) {
3663 zv = zend_hash_find_known_hash(CG(class_table), key);
3664 ce = new_ce;
3665 Z_CE_P(zv) = ce;
3666 }
3667 if (ht) {
3668 zend_hash_destroy(ht);
3669 FREE_HASHTABLE(ht);
3670 }
3671 }
3672
3673 if (!orig_record_errors) {
3674 zend_free_recorded_errors();
3675 }
3676 if (traits_and_interfaces) {
3677 free_alloca(traits_and_interfaces, use_heap);
3678 }
3679
3680 if (ZSTR_HAS_CE_CACHE(ce->name)) {
3681 ZSTR_SET_CE_CACHE(ce->name, ce);
3682 }
3683
3684 return ce;
3685 }
3686 /* }}} */
3687
3688 /* 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)3689 static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
3690 {
3691 zend_string *key;
3692 zend_function *parent_func;
3693 const zend_property_info *parent_info;
3694 const zend_class_constant *parent_const;
3695 inheritance_status overall_status = INHERITANCE_SUCCESS;
3696
3697 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3698 zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3699 if (zv) {
3700 zend_function *child_func = Z_FUNC_P(zv);
3701 inheritance_status status =
3702 do_inheritance_check_on_method(
3703 child_func, child_func->common.scope,
3704 parent_func, parent_func->common.scope,
3705 ce, NULL,
3706 ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3707 if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3708 overall_status = INHERITANCE_WARNING;
3709 } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3710 return status;
3711 }
3712 }
3713 } ZEND_HASH_FOREACH_END();
3714
3715 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3716 const zval *zv;
3717 if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3718 continue;
3719 }
3720
3721 zv = zend_hash_find_known_hash(&ce->properties_info, key);
3722 if (zv) {
3723 const zend_property_info *child_info = Z_PTR_P(zv);
3724 if (ZEND_TYPE_IS_SET(child_info->type)) {
3725 inheritance_status status = verify_property_type_compatibility(parent_info, child_info, prop_get_variance(parent_info), false, false);
3726 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3727 return status;
3728 }
3729 }
3730 }
3731 } ZEND_HASH_FOREACH_END();
3732
3733 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3734 const zval *zv;
3735 if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3736 continue;
3737 }
3738
3739 zv = zend_hash_find_known_hash(&ce->constants_table, key);
3740 if (zv) {
3741 const zend_class_constant *child_const = Z_PTR_P(zv);
3742 if (ZEND_TYPE_IS_SET(child_const->type)) {
3743 inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3744 ZEND_ASSERT(status != INHERITANCE_WARNING);
3745 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3746 return status;
3747 }
3748 }
3749 }
3750 } ZEND_HASH_FOREACH_END();
3751
3752 return overall_status;
3753 }
3754 /* }}} */
3755
register_early_bound_ce(zval * delayed_early_binding,zend_string * lcname,zend_class_entry * ce)3756 static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3757 if (delayed_early_binding) {
3758 if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3759 if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3760 Z_CE_P(delayed_early_binding) = ce;
3761 return true;
3762 }
3763 } else {
3764 /* If preloading is used, don't replace the existing bucket, add a new one. */
3765 if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3766 return true;
3767 }
3768 }
3769 zend_class_entry *old_ce = zend_hash_find_ptr(EG(class_table), lcname);
3770 ZEND_ASSERT(old_ce);
3771 zend_class_redeclaration_error(E_COMPILE_ERROR, old_ce);
3772 return false;
3773 }
3774 if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3775 return true;
3776 }
3777 return false;
3778 }
3779
zend_try_early_bind(zend_class_entry * ce,zend_class_entry * parent_ce,zend_string * lcname,zval * delayed_early_binding)3780 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) /* {{{ */
3781 {
3782 inheritance_status status;
3783 zend_class_entry *proto = NULL;
3784 zend_class_entry *orig_linking_class;
3785
3786 if (ce->ce_flags & ZEND_ACC_LINKED) {
3787 ZEND_ASSERT(ce->parent == NULL);
3788 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3789 return NULL;
3790 }
3791 zend_observer_class_linked_notify(ce, lcname);
3792 return ce;
3793 }
3794
3795 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3796 UPDATE_IS_CACHEABLE(parent_ce);
3797 if (is_cacheable) {
3798 if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3799 zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3800 if (ret) {
3801 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
3802 return NULL;
3803 }
3804 zend_observer_class_linked_notify(ret, lcname);
3805 return ret;
3806 }
3807 } else {
3808 is_cacheable = 0;
3809 }
3810 proto = ce;
3811 }
3812
3813 orig_linking_class = CG(current_linking_class);
3814 CG(current_linking_class) = NULL;
3815 status = zend_can_early_bind(ce, parent_ce);
3816 CG(current_linking_class) = orig_linking_class;
3817 if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3818 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3819 /* Lazy class loading */
3820 ce = zend_lazy_class_load(ce);
3821 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3822 /* Lazy class loading */
3823 ce = zend_lazy_class_load(ce);
3824 ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3825 }
3826
3827 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3828 return NULL;
3829 }
3830
3831 orig_linking_class = CG(current_linking_class);
3832 CG(current_linking_class) = is_cacheable ? ce : NULL;
3833
3834 zend_try{
3835 CG(zend_lineno) = ce->info.user.line_start;
3836
3837 if (is_cacheable) {
3838 zend_begin_record_errors();
3839 }
3840
3841 zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3842 if (parent_ce && parent_ce->num_interfaces) {
3843 zend_do_inherit_interfaces(ce, parent_ce);
3844 }
3845 zend_build_properties_info_table(ce);
3846 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) {
3847 zend_verify_abstract_class(ce);
3848 }
3849 zend_inheritance_check_override(ce);
3850 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3851 ce->ce_flags |= ZEND_ACC_LINKED;
3852
3853 CG(current_linking_class) = orig_linking_class;
3854 } zend_catch {
3855 EG(record_errors) = false;
3856 zend_free_recorded_errors();
3857 zend_bailout();
3858 } zend_end_try();
3859
3860 EG(record_errors) = false;
3861
3862 if (is_cacheable) {
3863 HashTable *ht = (HashTable*)ce->inheritance_cache;
3864 zend_class_entry *new_ce;
3865
3866 ce->inheritance_cache = NULL;
3867 new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3868 if (new_ce) {
3869 zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3870 ce = new_ce;
3871 Z_CE_P(zv) = ce;
3872 }
3873 if (ht) {
3874 zend_hash_destroy(ht);
3875 FREE_HASHTABLE(ht);
3876 }
3877 }
3878
3879 if (ZSTR_HAS_CE_CACHE(ce->name)) {
3880 ZSTR_SET_CE_CACHE(ce->name, ce);
3881 }
3882 zend_observer_class_linked_notify(ce, lcname);
3883
3884 return ce;
3885 }
3886 return NULL;
3887 }
3888 /* }}} */
3889