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