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 = (zend_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 #define ZEND_INHERITANCE_LAZY_CHILD_CLONE (1<<0)
1082 #define ZEND_INHERITANCE_CHECK_SILENT (1<<1) /* don't throw errors */
1083 #define ZEND_INHERITANCE_CHECK_PROTO (1<<2) /* check method prototype (it might be already checked before) */
1084 #define ZEND_INHERITANCE_CHECK_VISIBILITY (1<<3)
1085 #define ZEND_INHERITANCE_SET_CHILD_CHANGED (1<<4)
1086 #define ZEND_INHERITANCE_SET_CHILD_PROTO (1<<5)
1087 #define ZEND_INHERITANCE_RESET_CHILD_OVERRIDE (1<<6)
1088
do_inheritance_check_on_method(zend_function * child,zend_class_entry * child_scope,zend_function * parent,zend_class_entry * parent_scope,zend_class_entry * ce,zval * child_zv,uint32_t flags)1089 static inheritance_status do_inheritance_check_on_method(
1090 zend_function *child, zend_class_entry *child_scope,
1091 zend_function *parent, zend_class_entry *parent_scope,
1092 zend_class_entry *ce, zval *child_zv, uint32_t flags) /* {{{ */
1093 {
1094 uint32_t child_flags;
1095 uint32_t parent_flags = parent->common.fn_flags;
1096 zend_function *proto;
1097
1098 #define SEPARATE_METHOD() do { \
1099 if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1100 && child_scope != ce && child->type == ZEND_USER_FUNCTION) { \
1101 /* op_array wasn't duplicated yet */ \
1102 zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); \
1103 memcpy(new_function, child, sizeof(zend_op_array)); \
1104 Z_PTR_P(child_zv) = child = new_function; \
1105 flags &= ~ZEND_INHERITANCE_LAZY_CHILD_CLONE; \
1106 } \
1107 } while(0)
1108
1109 if (UNEXPECTED((parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_ABSTRACT|ZEND_ACC_CTOR)) == ZEND_ACC_PRIVATE)) {
1110 if (flags & ZEND_INHERITANCE_SET_CHILD_CHANGED) {
1111 SEPARATE_METHOD();
1112 child->common.fn_flags |= ZEND_ACC_CHANGED;
1113 }
1114 /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
1115 return INHERITANCE_SUCCESS;
1116 }
1117
1118 if ((flags & ZEND_INHERITANCE_CHECK_PROTO) && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
1119 if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1120 return INHERITANCE_ERROR;
1121 }
1122 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1123 "Cannot override final method %s::%s()",
1124 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
1125 }
1126
1127 child_flags = child->common.fn_flags;
1128 /* You cannot change from static to non static and vice versa.
1129 */
1130 if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1131 && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
1132 if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1133 return INHERITANCE_ERROR;
1134 }
1135 if (child_flags & ZEND_ACC_STATIC) {
1136 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1137 "Cannot make non static method %s::%s() static in class %s",
1138 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1139 } else {
1140 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1141 "Cannot make static method %s::%s() non static in class %s",
1142 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1143 }
1144 }
1145
1146 /* Disallow making an inherited method abstract. */
1147 if ((flags & ZEND_INHERITANCE_CHECK_PROTO)
1148 && UNEXPECTED((child_flags & ZEND_ACC_ABSTRACT) > (parent_flags & ZEND_ACC_ABSTRACT))) {
1149 if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1150 return INHERITANCE_ERROR;
1151 }
1152 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1153 "Cannot make non abstract method %s::%s() abstract in class %s",
1154 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
1155 }
1156
1157 if ((flags & ZEND_INHERITANCE_SET_CHILD_CHANGED)
1158 && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
1159 SEPARATE_METHOD();
1160 child->common.fn_flags |= ZEND_ACC_CHANGED;
1161 }
1162
1163 proto = parent->common.prototype ?
1164 parent->common.prototype : parent;
1165
1166 if (parent_flags & ZEND_ACC_CTOR) {
1167 /* ctors only have a prototype if is abstract (or comes from an interface) */
1168 /* and if that is the case, we want to check inheritance against it */
1169 if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1170 return INHERITANCE_SUCCESS;
1171 }
1172 parent = proto;
1173 }
1174
1175 if ((flags & ZEND_INHERITANCE_SET_CHILD_PROTO)
1176 && child->common.prototype != proto) {
1177 SEPARATE_METHOD();
1178 child->common.prototype = proto;
1179 }
1180
1181 /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1182 if ((flags & ZEND_INHERITANCE_CHECK_VISIBILITY)
1183 && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1184 if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1185 return INHERITANCE_ERROR;
1186 }
1187 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1188 "Access level to %s::%s() must be %s (as in class %s)%s",
1189 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");
1190 }
1191
1192 if (flags & ZEND_INHERITANCE_CHECK_PROTO) {
1193 if (flags & ZEND_INHERITANCE_CHECK_SILENT) {
1194 return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1195 }
1196 perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1197 }
1198
1199 if ((flags & ZEND_INHERITANCE_RESET_CHILD_OVERRIDE)
1200 && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1201 SEPARATE_METHOD();
1202 child->common.fn_flags &= ~ZEND_ACC_OVERRIDE;
1203 }
1204
1205 #undef SEPARATE_METHOD
1206
1207 return INHERITANCE_SUCCESS;
1208 }
1209 /* }}} */
1210
do_inherit_method(zend_string * key,zend_function * parent,zend_class_entry * ce,bool is_interface,uint32_t flags)1211 static void do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce, bool is_interface, uint32_t flags) /* {{{ */
1212 {
1213 zval *child = zend_hash_find_known_hash(&ce->function_table, key);
1214
1215 if (child) {
1216 zend_function *func = (zend_function*)Z_PTR_P(child);
1217
1218 if (is_interface && UNEXPECTED(func == parent)) {
1219 /* The same method in interface may be inherited few times */
1220 return;
1221 }
1222
1223 do_inheritance_check_on_method(
1224 func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1225 } else {
1226
1227 if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1228 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1229 }
1230
1231 parent = zend_duplicate_function(parent, ce);
1232
1233 if (!is_interface) {
1234 _zend_hash_append_ptr(&ce->function_table, key, parent);
1235 } else {
1236 zend_hash_add_new_ptr(&ce->function_table, key, parent);
1237 }
1238 }
1239 }
1240 /* }}} */
1241
property_types_compatible(const zend_property_info * parent_info,const zend_property_info * child_info)1242 static inheritance_status property_types_compatible(
1243 const zend_property_info *parent_info, const zend_property_info *child_info) {
1244 if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
1245 && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1246 return INHERITANCE_SUCCESS;
1247 }
1248
1249 if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1250 return INHERITANCE_ERROR;
1251 }
1252
1253 /* Perform a covariant type check in both directions to determined invariance. */
1254 inheritance_status status1 = zend_perform_covariant_type_check(
1255 child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1256 inheritance_status status2 = zend_perform_covariant_type_check(
1257 parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1258 if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1259 return INHERITANCE_SUCCESS;
1260 }
1261 if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1262 return INHERITANCE_ERROR;
1263 }
1264 ZEND_ASSERT(status1 == INHERITANCE_UNRESOLVED || status2 == INHERITANCE_UNRESOLVED);
1265 return INHERITANCE_UNRESOLVED;
1266 }
1267
emit_incompatible_property_error(const zend_property_info * child,const zend_property_info * parent)1268 static void emit_incompatible_property_error(
1269 const zend_property_info *child, const zend_property_info *parent) {
1270 zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1271 zend_error_noreturn(E_COMPILE_ERROR,
1272 "Type of %s::$%s must be %s (as in class %s)",
1273 ZSTR_VAL(child->ce->name),
1274 zend_get_unmangled_property_name(child->name),
1275 ZSTR_VAL(type_str),
1276 ZSTR_VAL(parent->ce->name));
1277 }
1278
do_inherit_property(zend_property_info * parent_info,zend_string * key,zend_class_entry * ce)1279 static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1280 {
1281 zval *child = zend_hash_find_known_hash(&ce->properties_info, key);
1282 zend_property_info *child_info;
1283
1284 if (UNEXPECTED(child)) {
1285 child_info = Z_PTR_P(child);
1286 if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1287 child_info->flags |= ZEND_ACC_CHANGED;
1288 }
1289 if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1290 if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
1291 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1292 (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1293 (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
1294 }
1295 if (UNEXPECTED((child_info->flags & ZEND_ACC_READONLY) != (parent_info->flags & ZEND_ACC_READONLY))) {
1296 zend_error_noreturn(E_COMPILE_ERROR,
1297 "Cannot redeclare %s property %s::$%s as %s %s::$%s",
1298 parent_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1299 ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1300 child_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1301 ZSTR_VAL(ce->name), ZSTR_VAL(key));
1302 }
1303
1304 if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1305 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");
1306 } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
1307 int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
1308 int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1309
1310 /* Don't keep default properties in GC (they may be freed by opcache) */
1311 zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1312 ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1313 ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1314 child_info->offset = parent_info->offset;
1315 }
1316
1317 if (ZEND_TYPE_IS_SET(parent_info->type)) {
1318 inheritance_status status = property_types_compatible(parent_info, child_info);
1319 if (status == INHERITANCE_ERROR) {
1320 emit_incompatible_property_error(child_info, parent_info);
1321 }
1322 if (status == INHERITANCE_UNRESOLVED) {
1323 add_property_compatibility_obligation(ce, child_info, parent_info);
1324 }
1325 } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1326 zend_error_noreturn(E_COMPILE_ERROR,
1327 "Type of %s::$%s must not be defined (as in class %s)",
1328 ZSTR_VAL(ce->name),
1329 ZSTR_VAL(key),
1330 ZSTR_VAL(parent_info->ce->name));
1331 }
1332 }
1333 } else {
1334 _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1335 }
1336 }
1337 /* }}} */
1338
do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1339 static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1340 {
1341 if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
1342 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));
1343 }
1344 /* This should be prevented by the class lookup logic. */
1345 ZEND_ASSERT(ce != iface);
1346 }
1347 /* }}} */
1348
zend_do_inherit_interfaces(zend_class_entry * ce,const zend_class_entry * iface)1349 static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1350 {
1351 /* expects interface to be contained in ce's interface list already */
1352 uint32_t i, ce_num, if_num = iface->num_interfaces;
1353 zend_class_entry *entry;
1354
1355 ce_num = ce->num_interfaces;
1356
1357 if (ce->type == ZEND_INTERNAL_CLASS) {
1358 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1359 } else {
1360 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1361 }
1362
1363 /* Inherit the interfaces, only if they're not already inherited by the class */
1364 while (if_num--) {
1365 entry = iface->interfaces[if_num];
1366 for (i = 0; i < ce_num; i++) {
1367 if (ce->interfaces[i] == entry) {
1368 break;
1369 }
1370 }
1371 if (i == ce_num) {
1372 ce->interfaces[ce->num_interfaces++] = entry;
1373 }
1374 }
1375 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1376
1377 /* and now call the implementing handlers */
1378 while (ce_num < ce->num_interfaces) {
1379 do_implement_interface(ce, ce->interfaces[ce_num++]);
1380 }
1381 }
1382 /* }}} */
1383
emit_incompatible_class_constant_error(const zend_class_constant * child,const zend_class_constant * parent,const zend_string * const_name)1384 static void emit_incompatible_class_constant_error(
1385 const zend_class_constant *child, const zend_class_constant *parent, const zend_string *const_name) {
1386 zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1387 zend_error_noreturn(E_COMPILE_ERROR,
1388 "Type of %s::%s must be compatible with %s::%s of type %s",
1389 ZSTR_VAL(child->ce->name),
1390 ZSTR_VAL(const_name),
1391 ZSTR_VAL(parent->ce->name),
1392 ZSTR_VAL(const_name),
1393 ZSTR_VAL(type_str));
1394 }
1395
class_constant_types_compatible(const zend_class_constant * parent,const zend_class_constant * child)1396 static inheritance_status class_constant_types_compatible(const zend_class_constant *parent, const zend_class_constant *child)
1397 {
1398 ZEND_ASSERT(ZEND_TYPE_IS_SET(parent->type));
1399
1400 if (!ZEND_TYPE_IS_SET(child->type)) {
1401 return INHERITANCE_ERROR;
1402 }
1403
1404 return zend_perform_covariant_type_check(child->ce, child->type, parent->ce, parent->type);
1405 }
1406
1407 static bool do_inherit_constant_check(
1408 zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name);
1409
do_inherit_class_constant(zend_string * name,zend_class_constant * parent_const,zend_class_entry * ce)1410 static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
1411 {
1412 zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1413 zend_class_constant *c;
1414
1415 if (zv != NULL) {
1416 c = (zend_class_constant*)Z_PTR_P(zv);
1417 bool inherit = do_inherit_constant_check(ce, parent_const, name);
1418 ZEND_ASSERT(!inherit);
1419 } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1420 if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1421 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1422 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1423 if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
1424 c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1425 memcpy(c, parent_const, sizeof(zend_class_constant));
1426 parent_const = c;
1427 Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1428 }
1429 }
1430 if (ce->type & ZEND_INTERNAL_CLASS) {
1431 c = pemalloc(sizeof(zend_class_constant), 1);
1432 memcpy(c, parent_const, sizeof(zend_class_constant));
1433 parent_const = c;
1434 }
1435 _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1436 }
1437 }
1438 /* }}} */
1439
zend_build_properties_info_table(zend_class_entry * ce)1440 void zend_build_properties_info_table(zend_class_entry *ce)
1441 {
1442 zend_property_info **table, *prop;
1443 size_t size;
1444 if (ce->default_properties_count == 0) {
1445 return;
1446 }
1447
1448 ZEND_ASSERT(ce->properties_info_table == NULL);
1449 size = sizeof(zend_property_info *) * ce->default_properties_count;
1450 if (ce->type == ZEND_USER_CLASS) {
1451 ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1452 } else {
1453 ce->properties_info_table = table = pemalloc(size, 1);
1454 }
1455
1456 /* Dead slots may be left behind during inheritance. Make sure these are NULLed out. */
1457 memset(table, 0, size);
1458
1459 if (ce->parent && ce->parent->default_properties_count != 0) {
1460 zend_property_info **parent_table = ce->parent->properties_info_table;
1461 memcpy(
1462 table, parent_table,
1463 sizeof(zend_property_info *) * ce->parent->default_properties_count
1464 );
1465
1466 /* Child did not add any new properties, we are done */
1467 if (ce->default_properties_count == ce->parent->default_properties_count) {
1468 return;
1469 }
1470 }
1471
1472 ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
1473 if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0) {
1474 table[OBJ_PROP_TO_NUM(prop->offset)] = prop;
1475 }
1476 } ZEND_HASH_FOREACH_END();
1477 }
1478
zend_do_inheritance_ex(zend_class_entry * ce,zend_class_entry * parent_ce,bool checked)1479 ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked) /* {{{ */
1480 {
1481 zend_property_info *property_info;
1482 zend_function *func;
1483 zend_string *key;
1484
1485 if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) {
1486 /* Interface can only inherit other interfaces */
1487 if (UNEXPECTED(!(parent_ce->ce_flags & ZEND_ACC_INTERFACE))) {
1488 zend_error_noreturn(E_COMPILE_ERROR, "Interface %s cannot extend class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1489 }
1490 } else if (UNEXPECTED(parent_ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_FINAL))) {
1491 /* Class must not extend a final class */
1492 if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1493 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1494 }
1495
1496 /* Class declaration must not extend traits or interfaces */
1497 if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1498 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1499 ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1500 );
1501 }
1502 }
1503
1504 if (UNEXPECTED((ce->ce_flags & ZEND_ACC_READONLY_CLASS) != (parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS))) {
1505 zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1506 ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1507 parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1508 );
1509 }
1510
1511 if (ce->parent_name) {
1512 zend_string_release_ex(ce->parent_name, 0);
1513 }
1514 ce->parent = parent_ce;
1515 ce->default_object_handlers = parent_ce->default_object_handlers;
1516 ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1517
1518 /* Inherit properties */
1519 if (parent_ce->default_properties_count) {
1520 zval *src, *dst, *end;
1521
1522 if (ce->default_properties_count) {
1523 zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1524 src = ce->default_properties_table + ce->default_properties_count;
1525 end = table + parent_ce->default_properties_count;
1526 dst = end + ce->default_properties_count;
1527 ce->default_properties_table = table;
1528 do {
1529 dst--;
1530 src--;
1531 ZVAL_COPY_VALUE_PROP(dst, src);
1532 } while (dst != end);
1533 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1534 end = ce->default_properties_table;
1535 } else {
1536 end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1537 dst = end + parent_ce->default_properties_count;
1538 ce->default_properties_table = end;
1539 }
1540 src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1541 if (UNEXPECTED(parent_ce->type != ce->type)) {
1542 /* User class extends internal */
1543 do {
1544 dst--;
1545 src--;
1546 /* We don't have to account for refcounting because
1547 * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1548 ZEND_ASSERT(!Z_REFCOUNTED_P(src));
1549 ZVAL_COPY_VALUE_PROP(dst, src);
1550 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1551 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1552 ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1553 }
1554 continue;
1555 } while (dst != end);
1556 } else {
1557 do {
1558 dst--;
1559 src--;
1560 ZVAL_COPY_PROP(dst, src);
1561 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1562 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1563 ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1564 }
1565 continue;
1566 } while (dst != end);
1567 }
1568 ce->default_properties_count += parent_ce->default_properties_count;
1569 }
1570
1571 if (parent_ce->default_static_members_count) {
1572 zval *src, *dst, *end;
1573
1574 if (ce->default_static_members_count) {
1575 zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1576 src = ce->default_static_members_table + ce->default_static_members_count;
1577 end = table + parent_ce->default_static_members_count;
1578 dst = end + ce->default_static_members_count;
1579 ce->default_static_members_table = table;
1580 do {
1581 dst--;
1582 src--;
1583 ZVAL_COPY_VALUE(dst, src);
1584 } while (dst != end);
1585 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1586 end = ce->default_static_members_table;
1587 } else {
1588 end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1589 dst = end + parent_ce->default_static_members_count;
1590 ce->default_static_members_table = end;
1591 }
1592 src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1593 do {
1594 dst--;
1595 src--;
1596 if (Z_TYPE_P(src) == IS_INDIRECT) {
1597 ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1598 } else {
1599 ZVAL_INDIRECT(dst, src);
1600 }
1601 if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1602 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1603 ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
1604 }
1605 } while (dst != end);
1606 ce->default_static_members_count += parent_ce->default_static_members_count;
1607 if (!ZEND_MAP_PTR(ce->static_members_table)) {
1608 if (ce->type == ZEND_INTERNAL_CLASS &&
1609 ce->info.internal.module->type == MODULE_PERSISTENT) {
1610 ZEND_MAP_PTR_NEW(ce->static_members_table);
1611 }
1612 }
1613 }
1614
1615 ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1616 if (property_info->ce == ce) {
1617 if (property_info->flags & ZEND_ACC_STATIC) {
1618 property_info->offset += parent_ce->default_static_members_count;
1619 } else {
1620 property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1621 }
1622 }
1623 } ZEND_HASH_FOREACH_END();
1624
1625 if (zend_hash_num_elements(&parent_ce->properties_info)) {
1626 zend_hash_extend(&ce->properties_info,
1627 zend_hash_num_elements(&ce->properties_info) +
1628 zend_hash_num_elements(&parent_ce->properties_info), 0);
1629
1630 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1631 do_inherit_property(property_info, key, ce);
1632 } ZEND_HASH_FOREACH_END();
1633 }
1634
1635 if (zend_hash_num_elements(&parent_ce->constants_table)) {
1636 zend_class_constant *c;
1637
1638 zend_hash_extend(&ce->constants_table,
1639 zend_hash_num_elements(&ce->constants_table) +
1640 zend_hash_num_elements(&parent_ce->constants_table), 0);
1641
1642 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
1643 do_inherit_class_constant(key, c, ce);
1644 } ZEND_HASH_FOREACH_END();
1645 }
1646
1647 if (zend_hash_num_elements(&parent_ce->function_table)) {
1648 zend_hash_extend(&ce->function_table,
1649 zend_hash_num_elements(&ce->function_table) +
1650 zend_hash_num_elements(&parent_ce->function_table), 0);
1651 uint32_t flags =
1652 ZEND_INHERITANCE_LAZY_CHILD_CLONE |
1653 ZEND_INHERITANCE_SET_CHILD_CHANGED |
1654 ZEND_INHERITANCE_SET_CHILD_PROTO |
1655 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
1656
1657 if (!checked) {
1658 flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
1659 }
1660 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1661 do_inherit_method(key, func, ce, 0, flags);
1662 } ZEND_HASH_FOREACH_END();
1663 }
1664
1665 do_inherit_parent_constructor(ce);
1666
1667 if (ce->type == ZEND_INTERNAL_CLASS) {
1668 if (parent_ce->num_interfaces) {
1669 zend_do_inherit_interfaces(ce, parent_ce);
1670 }
1671
1672 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1673 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1674 }
1675 }
1676 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);
1677 }
1678 /* }}} */
1679
check_trait_property_or_constant_value_compatibility(zend_class_entry * ce,zval * op1,zval * op2)1680 static zend_always_inline bool check_trait_property_or_constant_value_compatibility(zend_class_entry *ce, zval *op1, zval *op2) /* {{{ */
1681 {
1682 bool is_compatible;
1683 zval op1_tmp, op2_tmp;
1684
1685 /* if any of the values is a constant, we try to resolve it */
1686 if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
1687 ZVAL_COPY_OR_DUP(&op1_tmp, op1);
1688 if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
1689 zval_ptr_dtor(&op1_tmp);
1690 return false;
1691 }
1692 op1 = &op1_tmp;
1693 }
1694 if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
1695 ZVAL_COPY_OR_DUP(&op2_tmp, op2);
1696 if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
1697 zval_ptr_dtor(&op2_tmp);
1698 return false;
1699 }
1700 op2 = &op2_tmp;
1701 }
1702
1703 is_compatible = fast_is_identical_function(op1, op2);
1704
1705 if (op1 == &op1_tmp) {
1706 zval_ptr_dtor_nogc(&op1_tmp);
1707 }
1708 if (op2 == &op2_tmp) {
1709 zval_ptr_dtor_nogc(&op2_tmp);
1710 }
1711
1712 return is_compatible;
1713 }
1714 /* }}} */
1715
1716 /** @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)1717 static bool do_inherit_constant_check(
1718 zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name
1719 ) {
1720 zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
1721 if (zv == NULL) {
1722 return true;
1723 }
1724
1725 zend_class_constant *child_constant = Z_PTR_P(zv);
1726 if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
1727 zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
1728 ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
1729 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
1730 );
1731 }
1732
1733 if (child_constant->ce != parent_constant->ce && child_constant->ce != ce) {
1734 zend_error_noreturn(E_COMPILE_ERROR,
1735 "%s %s inherits both %s::%s and %s::%s, which is ambiguous",
1736 zend_get_object_type_uc(ce),
1737 ZSTR_VAL(ce->name),
1738 ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
1739 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
1740 }
1741
1742 if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(child_constant) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PPP_MASK))) {
1743 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in %s %s)%s",
1744 ZSTR_VAL(ce->name), ZSTR_VAL(name),
1745 zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_constant)),
1746 zend_get_object_type(parent_constant->ce),
1747 ZSTR_VAL(parent_constant->ce->name),
1748 (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PUBLIC) ? "" : " or weaker"
1749 );
1750 }
1751
1752 if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
1753 inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
1754 if (status == INHERITANCE_ERROR) {
1755 emit_incompatible_class_constant_error(child_constant, parent_constant, name);
1756 } else if (status == INHERITANCE_UNRESOLVED) {
1757 add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
1758 }
1759 }
1760
1761 return false;
1762 }
1763 /* }}} */
1764
do_inherit_iface_constant(zend_string * name,zend_class_constant * c,zend_class_entry * ce,zend_class_entry * iface)1765 static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1766 {
1767 if (do_inherit_constant_check(ce, c, name)) {
1768 zend_class_constant *ct;
1769 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
1770 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1771 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
1772 if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
1773 ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1774 memcpy(ct, c, sizeof(zend_class_constant));
1775 c = ct;
1776 Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
1777 }
1778 }
1779 if (ce->type & ZEND_INTERNAL_CLASS) {
1780 ct = pemalloc(sizeof(zend_class_constant), 1);
1781 memcpy(ct, c, sizeof(zend_class_constant));
1782 c = ct;
1783 }
1784 zend_hash_update_ptr(&ce->constants_table, name, c);
1785 }
1786 }
1787 /* }}} */
1788
do_interface_implementation(zend_class_entry * ce,zend_class_entry * iface)1789 static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1790 {
1791 zend_function *func;
1792 zend_string *key;
1793 zend_class_constant *c;
1794 uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
1795
1796 if (!(ce->ce_flags & ZEND_ACC_INTERFACE)) {
1797 /* We are not setting the prototype of overridden interface methods because of abstract
1798 * constructors. See Zend/tests/interface_constructor_prototype_001.phpt. */
1799 flags |=
1800 ZEND_INHERITANCE_LAZY_CHILD_CLONE |
1801 ZEND_INHERITANCE_SET_CHILD_PROTO |
1802 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
1803 } else {
1804 flags |=
1805 ZEND_INHERITANCE_LAZY_CHILD_CLONE |
1806 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
1807 }
1808
1809 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1810 do_inherit_iface_constant(key, c, ce, iface);
1811 } ZEND_HASH_FOREACH_END();
1812
1813 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
1814 do_inherit_method(key, func, ce, 1, flags);
1815 } ZEND_HASH_FOREACH_END();
1816
1817 do_implement_interface(ce, iface);
1818 if (iface->num_interfaces) {
1819 zend_do_inherit_interfaces(ce, iface);
1820 }
1821 }
1822 /* }}} */
1823
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1824 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1825 {
1826 uint32_t i, ignore = 0;
1827 uint32_t current_iface_num = ce->num_interfaces;
1828 uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
1829 zend_string *key;
1830 zend_class_constant *c;
1831
1832 ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
1833
1834 for (i = 0; i < ce->num_interfaces; i++) {
1835 if (ce->interfaces[i] == NULL) {
1836 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
1837 i--;
1838 } else if (ce->interfaces[i] == iface) {
1839 if (EXPECTED(i < parent_iface_num)) {
1840 ignore = 1;
1841 } else {
1842 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1843 }
1844 }
1845 }
1846 if (ignore) {
1847 /* Check for attempt to redeclare interface constants */
1848 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1849 do_inherit_constant_check(ce, c, key);
1850 } ZEND_HASH_FOREACH_END();
1851 } else {
1852 if (ce->num_interfaces >= current_iface_num) {
1853 if (ce->type == ZEND_INTERNAL_CLASS) {
1854 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1855 } else {
1856 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1857 }
1858 }
1859 ce->interfaces[ce->num_interfaces++] = iface;
1860
1861 do_interface_implementation(ce, iface);
1862 }
1863 }
1864 /* }}} */
1865
zend_do_implement_interfaces(zend_class_entry * ce,zend_class_entry ** interfaces)1866 static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
1867 {
1868 zend_class_entry *iface;
1869 uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
1870 uint32_t num_interfaces = num_parent_interfaces;
1871 zend_string *key;
1872 zend_class_constant *c;
1873 uint32_t i, j;
1874
1875 for (i = 0; i < ce->num_interfaces; i++) {
1876 iface = interfaces[num_parent_interfaces + i];
1877 if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
1878 add_dependency_obligation(ce, iface);
1879 }
1880 if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
1881 efree(interfaces);
1882 zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1883 return;
1884 }
1885 for (j = 0; j < num_interfaces; j++) {
1886 if (interfaces[j] == iface) {
1887 if (j >= num_parent_interfaces) {
1888 efree(interfaces);
1889 zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
1890 zend_get_object_type_uc(ce),
1891 ZSTR_VAL(ce->name),
1892 ZSTR_VAL(iface->name));
1893 return;
1894 }
1895 /* skip duplications */
1896 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1897 do_inherit_constant_check(ce, c, key);
1898 } ZEND_HASH_FOREACH_END();
1899
1900 iface = NULL;
1901 break;
1902 }
1903 }
1904 if (iface) {
1905 interfaces[num_interfaces] = iface;
1906 num_interfaces++;
1907 }
1908 }
1909
1910 if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
1911 for (i = 0; i < ce->num_interfaces; i++) {
1912 zend_string_release_ex(ce->interface_names[i].name, 0);
1913 zend_string_release_ex(ce->interface_names[i].lc_name, 0);
1914 }
1915 efree(ce->interface_names);
1916 }
1917
1918 ce->num_interfaces = num_interfaces;
1919 ce->interfaces = interfaces;
1920 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1921
1922 for (i = 0; i < num_parent_interfaces; i++) {
1923 do_implement_interface(ce, ce->interfaces[i]);
1924 }
1925 /* Note that new interfaces can be added during this loop due to interface inheritance.
1926 * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */
1927 for (; i < num_interfaces; i++) {
1928 do_interface_implementation(ce, ce->interfaces[i]);
1929 }
1930 }
1931 /* }}} */
1932
1933
zend_inheritance_check_override(zend_class_entry * ce)1934 void zend_inheritance_check_override(zend_class_entry *ce)
1935 {
1936 zend_function *f;
1937
1938 if (ce->ce_flags & ZEND_ACC_TRAIT) {
1939 return;
1940 }
1941
1942 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, f) {
1943 if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
1944 ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
1945
1946 zend_error_at_noreturn(
1947 E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
1948 "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
1949 ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
1950 }
1951 } ZEND_HASH_FOREACH_END();
1952 }
1953
1954
fixup_trait_scope(const zend_function * fn,zend_class_entry * ce)1955 static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
1956 {
1957 /* self in trait methods should be resolved to the using class, not the trait. */
1958 return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
1959 }
1960
zend_add_trait_method(zend_class_entry * ce,zend_string * name,zend_string * key,zend_function * fn)1961 static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
1962 {
1963 zend_function *existing_fn = NULL;
1964 zend_function *new_fn;
1965 bool check_inheritance = false;
1966
1967 if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
1968 /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
1969 * of where it is coming from there is no conflict and we do not need to add it again */
1970 if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
1971 (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
1972 (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1973 return;
1974 }
1975
1976 /* Abstract method signatures from the trait must be satisfied. */
1977 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1978 /* "abstract private" methods in traits were not available prior to PHP 8.
1979 * As such, "abstract protected" was sometimes used to indicate trait requirements,
1980 * even though the "implementing" method was private. Do not check visibility
1981 * requirements to maintain backwards-compatibility with such usage.
1982 */
1983 do_inheritance_check_on_method(
1984 existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
1985 ce, NULL, ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
1986 return;
1987 }
1988
1989 if (existing_fn->common.scope == ce) {
1990 /* members from the current class override trait methods */
1991 return;
1992 } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
1993 && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
1994 /* two traits can't define the same non-abstract method */
1995 zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
1996 ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
1997 ZSTR_VAL(ce->name), ZSTR_VAL(name),
1998 ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
1999 } else {
2000 check_inheritance = true;
2001 }
2002 }
2003
2004 if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
2005 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
2006 memcpy(new_fn, fn, sizeof(zend_internal_function));
2007 new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
2008 } else {
2009 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2010 memcpy(new_fn, fn, sizeof(zend_op_array));
2011 new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2012 }
2013 new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2014
2015 /* Reassign method name, in case it is an alias. */
2016 new_fn->common.function_name = name;
2017 function_add_ref(new_fn);
2018 fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2019 zend_add_magic_method(ce, fn, key);
2020
2021 if (check_inheritance) {
2022 /* Inherited members are overridden by members inserted by traits.
2023 * Check whether the trait method fulfills the inheritance requirements. */
2024 uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2025 if (!(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2026 flags |= ZEND_INHERITANCE_SET_CHILD_CHANGED |ZEND_INHERITANCE_SET_CHILD_PROTO |
2027 ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2028 }
2029 do_inheritance_check_on_method(
2030 fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce),
2031 ce, NULL, flags);
2032 }
2033 }
2034 /* }}} */
2035
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce)2036 static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2037 {
2038 if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
2039
2040 fn->common.scope = ce;
2041
2042 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2043 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2044 }
2045 if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2046 ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2047 }
2048 }
2049 }
2050 /* }}} */
2051
zend_traits_check_private_final_inheritance(uint32_t original_fn_flags,zend_function * fn_copy,zend_string * name)2052 static void zend_traits_check_private_final_inheritance(uint32_t original_fn_flags, zend_function *fn_copy, zend_string *name)
2053 {
2054 /* If the function was originally already private+final, then it will have already been warned about.
2055 * If the function became private+final only after applying modifiers, we need to emit the same warning. */
2056 if ((original_fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) != (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2057 && (fn_copy->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2058 && !zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2059 zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2060 }
2061 }
2062
zend_traits_copy_functions(zend_string * fnname,zend_function * fn,zend_class_entry * ce,HashTable * exclude_table,zend_class_entry ** aliases)2063 static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
2064 {
2065 zend_trait_alias *alias, **alias_ptr;
2066 zend_string *lcname;
2067 zend_function fn_copy;
2068 int i;
2069
2070 /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2071 if (ce->trait_aliases) {
2072 alias_ptr = ce->trait_aliases;
2073 alias = *alias_ptr;
2074 i = 0;
2075 while (alias) {
2076 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2077 if (alias->alias != NULL
2078 && fn->common.scope == aliases[i]
2079 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2080 ) {
2081 fn_copy = *fn;
2082 if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2083 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2084 } else {
2085 fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2086 }
2087
2088 zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2089
2090 lcname = zend_string_tolower(alias->alias);
2091 zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2092 zend_string_release_ex(lcname, 0);
2093 }
2094 alias_ptr++;
2095 alias = *alias_ptr;
2096 i++;
2097 }
2098 }
2099
2100 if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2101 /* is not in hashtable, thus, function is not to be excluded */
2102 memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
2103
2104 /* apply aliases which have not alias name, just setting visibility */
2105 if (ce->trait_aliases) {
2106 alias_ptr = ce->trait_aliases;
2107 alias = *alias_ptr;
2108 i = 0;
2109 while (alias) {
2110 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2111 if (alias->alias == NULL && alias->modifiers != 0
2112 && fn->common.scope == aliases[i]
2113 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
2114 ) {
2115 if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2116 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2117 } else {
2118 fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2119 }
2120 }
2121 alias_ptr++;
2122 alias = *alias_ptr;
2123 i++;
2124 }
2125 }
2126
2127 zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2128
2129 zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2130 }
2131 }
2132 /* }}} */
2133
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait,zend_class_entry ** traits)2134 static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait, zend_class_entry **traits) /* {{{ */
2135 {
2136 uint32_t i;
2137
2138 if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2139 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));
2140 return 0;
2141 }
2142
2143 for (i = 0; i < ce->num_traits; i++) {
2144 if (traits[i] == trait) {
2145 return i;
2146 }
2147 }
2148 zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
2149 return 0;
2150 }
2151 /* }}} */
2152
zend_traits_init_trait_structures(zend_class_entry * ce,zend_class_entry ** traits,HashTable *** exclude_tables_ptr,zend_class_entry *** aliases_ptr)2153 static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
2154 {
2155 size_t i, j = 0;
2156 zend_trait_precedence **precedences;
2157 zend_trait_precedence *cur_precedence;
2158 zend_trait_method_reference *cur_method_ref;
2159 zend_string *lc_trait_name;
2160 zend_string *lcname;
2161 HashTable **exclude_tables = NULL;
2162 zend_class_entry **aliases = NULL;
2163 zend_class_entry *trait;
2164
2165 /* resolve class references */
2166 if (ce->trait_precedences) {
2167 exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2168 i = 0;
2169 precedences = ce->trait_precedences;
2170 ce->trait_precedences = NULL;
2171 while ((cur_precedence = precedences[i])) {
2172 /** Resolve classes for all precedence operations. */
2173 cur_method_ref = &cur_precedence->trait_method;
2174 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2175 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2176 zend_string_release_ex(lc_trait_name, 0);
2177 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2178 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2179 }
2180 zend_check_trait_usage(ce, trait, traits);
2181
2182 /** Ensure that the preferred method is actually available. */
2183 lcname = zend_string_tolower(cur_method_ref->method_name);
2184 if (!zend_hash_exists(&trait->function_table, lcname)) {
2185 zend_error_noreturn(E_COMPILE_ERROR,
2186 "A precedence rule was defined for %s::%s but this method does not exist",
2187 ZSTR_VAL(trait->name),
2188 ZSTR_VAL(cur_method_ref->method_name));
2189 }
2190
2191 /** With the other traits, we are more permissive.
2192 We do not give errors for those. This allows to be more
2193 defensive in such definitions.
2194 However, we want to make sure that the insteadof declaration
2195 is consistent in itself.
2196 */
2197
2198 for (j = 0; j < cur_precedence->num_excludes; j++) {
2199 zend_string* class_name = cur_precedence->exclude_class_names[j];
2200 zend_class_entry *exclude_ce;
2201 uint32_t trait_num;
2202
2203 lc_trait_name = zend_string_tolower(class_name);
2204 exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2205 zend_string_release_ex(lc_trait_name, 0);
2206 if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2207 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2208 }
2209 trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2210 if (!exclude_tables[trait_num]) {
2211 ALLOC_HASHTABLE(exclude_tables[trait_num]);
2212 zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2213 }
2214 if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2215 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));
2216 }
2217
2218 /* make sure that the trait method is not from a class mentioned in
2219 exclude_from_classes, for consistency */
2220 if (trait == exclude_ce) {
2221 zend_error_noreturn(E_COMPILE_ERROR,
2222 "Inconsistent insteadof definition. "
2223 "The method %s is to be used from %s, but %s is also on the exclude list",
2224 ZSTR_VAL(cur_method_ref->method_name),
2225 ZSTR_VAL(trait->name),
2226 ZSTR_VAL(trait->name));
2227 }
2228 }
2229 zend_string_release_ex(lcname, 0);
2230 i++;
2231 }
2232 ce->trait_precedences = precedences;
2233 }
2234
2235 if (ce->trait_aliases) {
2236 i = 0;
2237 while (ce->trait_aliases[i]) {
2238 i++;
2239 }
2240 aliases = ecalloc(i, sizeof(zend_class_entry*));
2241 i = 0;
2242 while (ce->trait_aliases[i]) {
2243 zend_trait_alias *cur_alias = ce->trait_aliases[i];
2244 cur_method_ref = &ce->trait_aliases[i]->trait_method;
2245 lcname = zend_string_tolower(cur_method_ref->method_name);
2246 if (cur_method_ref->class_name) {
2247 /* For all aliases with an explicit class name, resolve the class now. */
2248 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2249 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2250 zend_string_release_ex(lc_trait_name, 0);
2251 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2252 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2253 }
2254 zend_check_trait_usage(ce, trait, traits);
2255 aliases[i] = trait;
2256
2257 /* And, ensure that the referenced method is resolvable, too. */
2258 if (!zend_hash_exists(&trait->function_table, lcname)) {
2259 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));
2260 }
2261 } else {
2262 /* Find out which trait this method refers to. */
2263 trait = NULL;
2264 for (j = 0; j < ce->num_traits; j++) {
2265 if (traits[j]) {
2266 if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2267 if (!trait) {
2268 trait = traits[j];
2269 continue;
2270 }
2271
2272 zend_error_noreturn(E_COMPILE_ERROR,
2273 "An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
2274 ZSTR_VAL(cur_method_ref->method_name),
2275 ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2276 ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2277 ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2278 }
2279 }
2280 }
2281
2282 /* Non-absolute method reference refers to method that does not exist. */
2283 if (!trait) {
2284 if (cur_alias->alias) {
2285 zend_error_noreturn(E_COMPILE_ERROR,
2286 "An alias (%s) was defined for method %s(), but this method does not exist",
2287 ZSTR_VAL(cur_alias->alias),
2288 ZSTR_VAL(cur_alias->trait_method.method_name));
2289 } else {
2290 zend_error_noreturn(E_COMPILE_ERROR,
2291 "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2292 ZSTR_VAL(cur_alias->trait_method.method_name));
2293 }
2294 }
2295
2296 aliases[i] = trait;
2297 }
2298 zend_string_release_ex(lcname, 0);
2299 i++;
2300 }
2301 }
2302
2303 *exclude_tables_ptr = exclude_tables;
2304 *aliases_ptr = aliases;
2305 }
2306 /* }}} */
2307
zend_do_traits_method_binding(zend_class_entry * ce,zend_class_entry ** traits,HashTable ** exclude_tables,zend_class_entry ** aliases)2308 static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
2309 {
2310 uint32_t i;
2311 zend_string *key;
2312 zend_function *fn;
2313
2314 if (exclude_tables) {
2315 for (i = 0; i < ce->num_traits; i++) {
2316 if (traits[i]) {
2317 /* copies functions, applies defined aliasing, and excludes unused trait methods */
2318 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2319 zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2320 } ZEND_HASH_FOREACH_END();
2321
2322 if (exclude_tables[i]) {
2323 zend_hash_destroy(exclude_tables[i]);
2324 FREE_HASHTABLE(exclude_tables[i]);
2325 exclude_tables[i] = NULL;
2326 }
2327 }
2328 }
2329 } else {
2330 for (i = 0; i < ce->num_traits; i++) {
2331 if (traits[i]) {
2332 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2333 zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2334 } ZEND_HASH_FOREACH_END();
2335 }
2336 }
2337 }
2338
2339 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
2340 zend_fixup_trait_method(fn, ce);
2341 } ZEND_HASH_FOREACH_END();
2342 }
2343 /* }}} */
2344
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)2345 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) /* {{{ */
2346 {
2347 /* This function is used to show the place of the existing conflicting
2348 * definition in error messages when conflicts occur. Since trait constants
2349 * are flattened into the constants table of the composing class, and thus
2350 * we lose information about which constant was defined in which trait, a
2351 * process like this is needed to find the location of the first definition
2352 * of the constant from traits.
2353 */
2354 size_t i;
2355
2356 if (colliding_ce == ce) {
2357 for (i = 0; i < current_trait; i++) {
2358 if (traits[i]
2359 && zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2360 return traits[i];
2361 }
2362 }
2363 }
2364 /* Traits don't have it, then the composing class (or trait) itself has it. */
2365 return colliding_ce;
2366 }
2367 /* }}} */
2368
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)2369 static void emit_incompatible_trait_constant_error(
2370 zend_class_entry *ce, zend_class_constant *existing_constant, zend_class_constant *trait_constant, zend_string *name,
2371 zend_class_entry **traits, size_t current_trait
2372 ) {
2373 zend_error_noreturn(E_COMPILE_ERROR,
2374 "%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2375 ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2376 ZSTR_VAL(trait_constant->ce->name),
2377 ZSTR_VAL(name),
2378 ZSTR_VAL(ce->name)
2379 );
2380 }
2381
do_trait_constant_check(zend_class_entry * ce,zend_class_constant * trait_constant,zend_string * name,zend_class_entry ** traits,size_t current_trait)2382 static bool do_trait_constant_check(
2383 zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait
2384 ) {
2385 uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2386
2387 zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2388 if (zv == NULL) {
2389 /* No existing constant of the same name, so this one can be added */
2390 return true;
2391 }
2392
2393 zend_class_constant *existing_constant = Z_PTR_P(zv);
2394
2395 if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2396 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2397 return false;
2398 }
2399
2400 if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) {
2401 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2402 return false;
2403 } else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2404 inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2405 inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2406 if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
2407 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2408 return false;
2409 }
2410 }
2411
2412 if (!check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &existing_constant->value)) {
2413 /* There is an existing constant of the same name, and it conflicts with the new one, so let's throw a fatal error */
2414 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2415 return false;
2416 }
2417
2418 /* There is an existing constant which is compatible with the new one, so no need to add it */
2419 return false;
2420 }
2421
zend_do_traits_constant_binding(zend_class_entry * ce,zend_class_entry ** traits)2422 static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2423 {
2424 size_t i;
2425
2426 for (i = 0; i < ce->num_traits; i++) {
2427 zend_string *constant_name;
2428 zend_class_constant *constant;
2429
2430 if (!traits[i]) {
2431 continue;
2432 }
2433
2434 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2435 if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2436 zend_class_constant *ct = NULL;
2437
2438 ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2439 memcpy(ct, constant, sizeof(zend_class_constant));
2440 constant = ct;
2441
2442 if (Z_TYPE(constant->value) == IS_CONSTANT_AST) {
2443 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2444 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2445 }
2446
2447 /* Unlike interface implementations and class inheritances,
2448 * access control of the trait constants is done by the scope
2449 * of the composing class. So let's replace the ce here.
2450 */
2451 constant->ce = ce;
2452
2453 Z_TRY_ADDREF(constant->value);
2454 constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2455 if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2456 GC_ADDREF(constant->attributes);
2457 }
2458
2459 zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2460 }
2461 } ZEND_HASH_FOREACH_END();
2462 }
2463 }
2464 /* }}} */
2465
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)2466 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) /* {{{ */
2467 {
2468 size_t i;
2469
2470 if (colliding_ce == ce) {
2471 for (i = 0; i < current_trait; i++) {
2472 if (traits[i]
2473 && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2474 return traits[i];
2475 }
2476 }
2477 }
2478
2479 return colliding_ce;
2480 }
2481 /* }}} */
2482
zend_do_traits_property_binding(zend_class_entry * ce,zend_class_entry ** traits)2483 static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2484 {
2485 size_t i;
2486 zend_property_info *property_info;
2487 zend_property_info *colliding_prop;
2488 zend_property_info *new_prop;
2489 zend_string* prop_name;
2490 zval* prop_value;
2491 zend_string *doc_comment;
2492
2493 /* In the following steps the properties are inserted into the property table
2494 * for that, a very strict approach is applied:
2495 * - check for compatibility, if not compatible with any property in class -> fatal
2496 * - if compatible, then strict notice
2497 */
2498 for (i = 0; i < ce->num_traits; i++) {
2499 if (!traits[i]) {
2500 continue;
2501 }
2502 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2503 uint32_t flags = property_info->flags;
2504
2505 /* next: check for conflicts with current class */
2506 if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2507 if ((colliding_prop->flags & ZEND_ACC_PRIVATE) && colliding_prop->ce != ce) {
2508 zend_hash_del(&ce->properties_info, prop_name);
2509 flags |= ZEND_ACC_CHANGED;
2510 } else {
2511 bool is_compatible = false;
2512 uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2513
2514 if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2515 property_types_compatible(property_info, colliding_prop) == INHERITANCE_SUCCESS
2516 ) {
2517 /* the flags are identical, thus, the properties may be compatible */
2518 zval *op1, *op2;
2519
2520 if (flags & ZEND_ACC_STATIC) {
2521 op1 = &ce->default_static_members_table[colliding_prop->offset];
2522 op2 = &traits[i]->default_static_members_table[property_info->offset];
2523 ZVAL_DEINDIRECT(op1);
2524 ZVAL_DEINDIRECT(op2);
2525 } else {
2526 op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2527 op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2528 }
2529 is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2530 }
2531
2532 if (!is_compatible) {
2533 zend_error_noreturn(E_COMPILE_ERROR,
2534 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2535 ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2536 ZSTR_VAL(property_info->ce->name),
2537 ZSTR_VAL(prop_name),
2538 ZSTR_VAL(ce->name));
2539 }
2540 if (!(flags & ZEND_ACC_STATIC)) {
2541 continue;
2542 }
2543 }
2544 }
2545
2546 if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS) && !(property_info->flags & ZEND_ACC_READONLY)) {
2547 zend_error_noreturn(E_COMPILE_ERROR,
2548 "Readonly class %s cannot use trait with a non-readonly property %s::$%s",
2549 ZSTR_VAL(ce->name),
2550 ZSTR_VAL(property_info->ce->name),
2551 ZSTR_VAL(prop_name)
2552 );
2553 }
2554
2555 /* property not found, so lets add it */
2556 if (flags & ZEND_ACC_STATIC) {
2557 prop_value = &traits[i]->default_static_members_table[property_info->offset];
2558 ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2559 } else {
2560 prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2561 }
2562
2563 Z_TRY_ADDREF_P(prop_value);
2564 doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2565
2566 zend_type type = property_info->type;
2567 /* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2568 zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2569 new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2570
2571 if (property_info->attributes) {
2572 new_prop->attributes = property_info->attributes;
2573
2574 if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2575 GC_ADDREF(new_prop->attributes);
2576 }
2577 }
2578 } ZEND_HASH_FOREACH_END();
2579 }
2580 }
2581 /* }}} */
2582
zend_do_bind_traits(zend_class_entry * ce,zend_class_entry ** traits)2583 static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2584 {
2585 HashTable **exclude_tables;
2586 zend_class_entry **aliases;
2587
2588 ZEND_ASSERT(ce->num_traits > 0);
2589
2590 /* complete initialization of trait structures in ce */
2591 zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases);
2592
2593 /* first care about all methods to be flattened into the class */
2594 zend_do_traits_method_binding(ce, traits, exclude_tables, aliases);
2595
2596 if (aliases) {
2597 efree(aliases);
2598 }
2599
2600 if (exclude_tables) {
2601 efree(exclude_tables);
2602 }
2603
2604 /* then flatten the constants and properties into it, to, mostly to notify developer about problems */
2605 zend_do_traits_constant_binding(ce, traits);
2606 zend_do_traits_property_binding(ce, traits);
2607 }
2608 /* }}} */
2609
2610 #define MAX_ABSTRACT_INFO_CNT 3
2611 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
2612 #define DISPLAY_ABSTRACT_FN(idx) \
2613 ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
2614 ai.afn[idx] ? "::" : "", \
2615 ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
2616 ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
2617
2618 typedef struct _zend_abstract_info {
2619 zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
2620 int cnt;
2621 } zend_abstract_info;
2622
zend_verify_abstract_class_function(zend_function * fn,zend_abstract_info * ai)2623 static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai) /* {{{ */
2624 {
2625 if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
2626 ai->afn[ai->cnt] = fn;
2627 }
2628 ai->cnt++;
2629 }
2630 /* }}} */
2631
zend_verify_abstract_class(zend_class_entry * ce)2632 void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
2633 {
2634 zend_function *func;
2635 zend_abstract_info ai;
2636 bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
2637 bool can_be_abstract = (ce->ce_flags & ZEND_ACC_ENUM) == 0;
2638 memset(&ai, 0, sizeof(ai));
2639
2640 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
2641 if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
2642 /* If the class is explicitly abstract, we only check private abstract methods,
2643 * because only they must be declared in the same class. */
2644 if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
2645 zend_verify_abstract_class_function(func, &ai);
2646 }
2647 }
2648 } ZEND_HASH_FOREACH_END();
2649
2650 if (ai.cnt) {
2651 zend_error_noreturn(E_ERROR, !is_explicit_abstract && can_be_abstract
2652 ? "%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 ")"
2653 : "%s %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
2654 zend_get_object_type_uc(ce),
2655 ZSTR_VAL(ce->name), ai.cnt,
2656 ai.cnt > 1 ? "s" : "",
2657 DISPLAY_ABSTRACT_FN(0),
2658 DISPLAY_ABSTRACT_FN(1),
2659 DISPLAY_ABSTRACT_FN(2)
2660 );
2661 } else {
2662 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
2663 ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2664 }
2665 }
2666 /* }}} */
2667
2668 typedef struct {
2669 enum {
2670 OBLIGATION_DEPENDENCY,
2671 OBLIGATION_COMPATIBILITY,
2672 OBLIGATION_PROPERTY_COMPATIBILITY,
2673 OBLIGATION_CLASS_CONSTANT_COMPATIBILITY
2674 } type;
2675 union {
2676 zend_class_entry *dependency_ce;
2677 struct {
2678 /* Traits may use temporary on-stack functions during inheritance checks,
2679 * so use copies of functions here as well. */
2680 zend_function parent_fn;
2681 zend_function child_fn;
2682 zend_class_entry *child_scope;
2683 zend_class_entry *parent_scope;
2684 };
2685 struct {
2686 const zend_property_info *parent_prop;
2687 const zend_property_info *child_prop;
2688 };
2689 struct {
2690 const zend_string *const_name;
2691 const zend_class_constant *parent_const;
2692 const zend_class_constant *child_const;
2693 };
2694 };
2695 } variance_obligation;
2696
variance_obligation_dtor(zval * zv)2697 static void variance_obligation_dtor(zval *zv) {
2698 efree(Z_PTR_P(zv));
2699 }
2700
variance_obligation_ht_dtor(zval * zv)2701 static void variance_obligation_ht_dtor(zval *zv) {
2702 zend_hash_destroy(Z_PTR_P(zv));
2703 FREE_HASHTABLE(Z_PTR_P(zv));
2704 }
2705
get_or_init_obligations_for_class(zend_class_entry * ce)2706 static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
2707 HashTable *ht;
2708 zend_ulong key;
2709 if (!CG(delayed_variance_obligations)) {
2710 ALLOC_HASHTABLE(CG(delayed_variance_obligations));
2711 zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
2712 }
2713
2714 key = (zend_ulong) (uintptr_t) ce;
2715 ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
2716 if (ht) {
2717 return ht;
2718 }
2719
2720 ALLOC_HASHTABLE(ht);
2721 zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
2722 zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
2723 ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
2724 return ht;
2725 }
2726
add_dependency_obligation(zend_class_entry * ce,zend_class_entry * dependency_ce)2727 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
2728 HashTable *obligations = get_or_init_obligations_for_class(ce);
2729 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2730 obligation->type = OBLIGATION_DEPENDENCY;
2731 obligation->dependency_ce = dependency_ce;
2732 zend_hash_next_index_insert_ptr(obligations, obligation);
2733 }
2734
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)2735 static void add_compatibility_obligation(
2736 zend_class_entry *ce,
2737 const zend_function *child_fn, zend_class_entry *child_scope,
2738 const zend_function *parent_fn, zend_class_entry *parent_scope) {
2739 HashTable *obligations = get_or_init_obligations_for_class(ce);
2740 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2741 obligation->type = OBLIGATION_COMPATIBILITY;
2742 /* Copy functions, because they may be stack-allocated in the case of traits. */
2743 if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
2744 memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
2745 } else {
2746 memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
2747 }
2748 if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
2749 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
2750 } else {
2751 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
2752 }
2753 obligation->child_scope = child_scope;
2754 obligation->parent_scope = parent_scope;
2755 zend_hash_next_index_insert_ptr(obligations, obligation);
2756 }
2757
add_property_compatibility_obligation(zend_class_entry * ce,const zend_property_info * child_prop,const zend_property_info * parent_prop)2758 static void add_property_compatibility_obligation(
2759 zend_class_entry *ce, const zend_property_info *child_prop,
2760 const zend_property_info *parent_prop) {
2761 HashTable *obligations = get_or_init_obligations_for_class(ce);
2762 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2763 obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
2764 obligation->child_prop = child_prop;
2765 obligation->parent_prop = parent_prop;
2766 zend_hash_next_index_insert_ptr(obligations, obligation);
2767 }
2768
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)2769 static void add_class_constant_compatibility_obligation(
2770 zend_class_entry *ce, const zend_class_constant *child_const,
2771 const zend_class_constant *parent_const, const zend_string *const_name) {
2772 HashTable *obligations = get_or_init_obligations_for_class(ce);
2773 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2774 obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY;
2775 obligation->const_name = const_name;
2776 obligation->child_const = child_const;
2777 obligation->parent_const = parent_const;
2778 zend_hash_next_index_insert_ptr(obligations, obligation);
2779 }
2780
2781 static void resolve_delayed_variance_obligations(zend_class_entry *ce);
2782
check_variance_obligation(variance_obligation * obligation)2783 static void check_variance_obligation(variance_obligation *obligation) {
2784 if (obligation->type == OBLIGATION_DEPENDENCY) {
2785 zend_class_entry *dependency_ce = obligation->dependency_ce;
2786 if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
2787 zend_class_entry *orig_linking_class = CG(current_linking_class);
2788
2789 CG(current_linking_class) =
2790 (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
2791 resolve_delayed_variance_obligations(dependency_ce);
2792 CG(current_linking_class) = orig_linking_class;
2793 }
2794 } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
2795 inheritance_status status = zend_do_perform_implementation_check(
2796 &obligation->child_fn, obligation->child_scope,
2797 &obligation->parent_fn, obligation->parent_scope);
2798 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
2799 emit_incompatible_method_error(
2800 &obligation->child_fn, obligation->child_scope,
2801 &obligation->parent_fn, obligation->parent_scope, status);
2802 }
2803 /* Either the compatibility check was successful or only threw a warning. */
2804 } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
2805 inheritance_status status =
2806 property_types_compatible(obligation->parent_prop, obligation->child_prop);
2807 if (status != INHERITANCE_SUCCESS) {
2808 emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop);
2809 }
2810 } else {
2811 ZEND_ASSERT(obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY);
2812 inheritance_status status =
2813 class_constant_types_compatible(obligation->parent_const, obligation->child_const);
2814 if (status != INHERITANCE_SUCCESS) {
2815 emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name);
2816 }
2817 }
2818 }
2819
load_delayed_classes(zend_class_entry * ce)2820 static void load_delayed_classes(zend_class_entry *ce) {
2821 HashTable *delayed_autoloads = CG(delayed_autoloads);
2822 if (!delayed_autoloads) {
2823 return;
2824 }
2825
2826 /* Autoloading can trigger linking of another class, which may register new delayed autoloads.
2827 * For that reason, this code uses a loop that pops and loads the first element of the HT. If
2828 * this triggers linking, then the remaining classes may get loaded when linking the newly
2829 * loaded class. This is important, as otherwise necessary dependencies may not be available
2830 * if the new class is lower in the hierarchy than the current one. */
2831 HashPosition pos = 0;
2832 zend_string *name;
2833 zend_ulong idx;
2834 while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
2835 != HASH_KEY_NON_EXISTENT) {
2836 zend_string_addref(name);
2837 zend_hash_del(delayed_autoloads, name);
2838 zend_lookup_class(name);
2839 zend_string_release(name);
2840 if (EG(exception)) {
2841 zend_exception_uncaught_error(
2842 "During inheritance of %s, while autoloading %s",
2843 ZSTR_VAL(ce->name), ZSTR_VAL(name));
2844 }
2845 }
2846 }
2847
resolve_delayed_variance_obligations(zend_class_entry * ce)2848 static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
2849 HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
2850 zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
2851
2852 ZEND_ASSERT(all_obligations != NULL);
2853 obligations = zend_hash_index_find_ptr(all_obligations, num_key);
2854 ZEND_ASSERT(obligations != NULL);
2855
2856 variance_obligation *obligation;
2857 ZEND_HASH_FOREACH_PTR(obligations, obligation) {
2858 check_variance_obligation(obligation);
2859 } ZEND_HASH_FOREACH_END();
2860
2861 zend_inheritance_check_override(ce);
2862
2863 ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
2864 ce->ce_flags |= ZEND_ACC_LINKED;
2865 zend_hash_index_del(all_obligations, num_key);
2866 }
2867
check_unrecoverable_load_failure(zend_class_entry * ce)2868 static void check_unrecoverable_load_failure(zend_class_entry *ce) {
2869 /* If this class has been used while unlinked through a variance obligation, it is not legal
2870 * to remove the class from the class table and throw an exception, because there is already
2871 * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
2872 * a fatal error, as would happen if we did not allow exceptions in the first place. */
2873 if (CG(unlinked_uses)
2874 && zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t)ce) == SUCCESS) {
2875 zend_exception_uncaught_error(
2876 "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
2877 }
2878 }
2879
2880 #define zend_update_inherited_handler(handler) do { \
2881 if (ce->handler == (zend_function*)op_array) { \
2882 ce->handler = (zend_function*)new_op_array; \
2883 } \
2884 } while (0)
2885
zend_lazy_class_load(zend_class_entry * pce)2886 static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
2887 {
2888 zend_class_entry *ce;
2889 Bucket *p, *end;
2890
2891 ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
2892 memcpy(ce, pce, sizeof(zend_class_entry));
2893 ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
2894 ce->refcount = 1;
2895 ce->inheritance_cache = NULL;
2896 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
2897 ZEND_MAP_PTR_NEW(ce->mutable_data);
2898 } else {
2899 ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
2900 }
2901
2902 /* properties */
2903 if (ce->default_properties_table) {
2904 zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
2905 zval *src = ce->default_properties_table;
2906 zval *end = src + ce->default_properties_count;
2907
2908 ce->default_properties_table = dst;
2909 for (; src != end; src++, dst++) {
2910 ZVAL_COPY_VALUE_PROP(dst, src);
2911 }
2912 }
2913
2914 /* methods */
2915 ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
2916 if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
2917 p = emalloc(HT_SIZE(&ce->function_table));
2918 memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
2919 HT_SET_DATA_ADDR(&ce->function_table, p);
2920 p = ce->function_table.arData;
2921 end = p + ce->function_table.nNumUsed;
2922 for (; p != end; p++) {
2923 zend_op_array *op_array, *new_op_array;
2924
2925 op_array = Z_PTR(p->val);
2926 ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
2927 ZEND_ASSERT(op_array->scope == pce);
2928 ZEND_ASSERT(op_array->prototype == NULL);
2929 new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2930 Z_PTR(p->val) = new_op_array;
2931 memcpy(new_op_array, op_array, sizeof(zend_op_array));
2932 new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
2933 new_op_array->scope = ce;
2934 ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
2935 ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
2936
2937 zend_update_inherited_handler(constructor);
2938 zend_update_inherited_handler(destructor);
2939 zend_update_inherited_handler(clone);
2940 zend_update_inherited_handler(__get);
2941 zend_update_inherited_handler(__set);
2942 zend_update_inherited_handler(__call);
2943 zend_update_inherited_handler(__isset);
2944 zend_update_inherited_handler(__unset);
2945 zend_update_inherited_handler(__tostring);
2946 zend_update_inherited_handler(__callstatic);
2947 zend_update_inherited_handler(__debugInfo);
2948 zend_update_inherited_handler(__serialize);
2949 zend_update_inherited_handler(__unserialize);
2950 }
2951 }
2952
2953 /* static members */
2954 if (ce->default_static_members_table) {
2955 zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
2956 zval *src = ce->default_static_members_table;
2957 zval *end = src + ce->default_static_members_count;
2958
2959 ce->default_static_members_table = dst;
2960 for (; src != end; src++, dst++) {
2961 ZVAL_COPY_VALUE(dst, src);
2962 }
2963 }
2964 ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
2965
2966 /* properties_info */
2967 if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
2968 p = emalloc(HT_SIZE(&ce->properties_info));
2969 memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
2970 HT_SET_DATA_ADDR(&ce->properties_info, p);
2971 p = ce->properties_info.arData;
2972 end = p + ce->properties_info.nNumUsed;
2973 for (; p != end; p++) {
2974 zend_property_info *prop_info, *new_prop_info;
2975
2976 prop_info = Z_PTR(p->val);
2977 ZEND_ASSERT(prop_info->ce == pce);
2978 new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
2979 Z_PTR(p->val) = new_prop_info;
2980 memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
2981 new_prop_info->ce = ce;
2982 /* Deep copy the type information */
2983 zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
2984 }
2985 }
2986
2987 /* constants table */
2988 if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
2989 p = emalloc(HT_SIZE(&ce->constants_table));
2990 memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
2991 HT_SET_DATA_ADDR(&ce->constants_table, p);
2992 p = ce->constants_table.arData;
2993 end = p + ce->constants_table.nNumUsed;
2994 for (; p != end; p++) {
2995 zend_class_constant *c, *new_c;
2996
2997 c = Z_PTR(p->val);
2998 ZEND_ASSERT(c->ce == pce);
2999 new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3000 Z_PTR(p->val) = new_c;
3001 memcpy(new_c, c, sizeof(zend_class_constant));
3002 new_c->ce = ce;
3003 }
3004 }
3005
3006 return ce;
3007 }
3008
3009 #ifndef ZEND_WIN32
3010 # define UPDATE_IS_CACHEABLE(ce) do { \
3011 if ((ce)->type == ZEND_USER_CLASS) { \
3012 is_cacheable &= (ce)->ce_flags; \
3013 } \
3014 } while (0)
3015 #else
3016 // TODO: ASLR may cause different addresses in different workers ???
3017 # define UPDATE_IS_CACHEABLE(ce) do { \
3018 is_cacheable &= (ce)->ce_flags; \
3019 } while (0)
3020 #endif
3021
zend_do_link_class(zend_class_entry * ce,zend_string * lc_parent_name,zend_string * key)3022 ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key) /* {{{ */
3023 {
3024 /* Load parent/interface dependencies first, so we can still gracefully abort linking
3025 * with an exception and remove the class from the class table. This is only possible
3026 * if no variance obligations on the current class have been added during autoloading. */
3027 zend_class_entry *parent = NULL;
3028 zend_class_entry **traits_and_interfaces = NULL;
3029 zend_class_entry *proto = NULL;
3030 zend_class_entry *orig_linking_class;
3031 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3032 uint32_t i, j;
3033 zval *zv;
3034 ALLOCA_FLAG(use_heap)
3035
3036 SET_ALLOCA_FLAG(use_heap);
3037 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3038
3039 if (ce->parent_name) {
3040 parent = zend_fetch_class_by_name(
3041 ce->parent_name, lc_parent_name,
3042 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3043 if (!parent) {
3044 check_unrecoverable_load_failure(ce);
3045 return NULL;
3046 }
3047 UPDATE_IS_CACHEABLE(parent);
3048 }
3049
3050 if (ce->num_traits || ce->num_interfaces) {
3051 traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3052
3053 for (i = 0; i < ce->num_traits; i++) {
3054 zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3055 ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
3056 if (UNEXPECTED(trait == NULL)) {
3057 free_alloca(traits_and_interfaces, use_heap);
3058 return NULL;
3059 }
3060 if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
3061 zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
3062 free_alloca(traits_and_interfaces, use_heap);
3063 return NULL;
3064 }
3065 for (j = 0; j < i; j++) {
3066 if (traits_and_interfaces[j] == trait) {
3067 /* skip duplications */
3068 trait = NULL;
3069 break;
3070 }
3071 }
3072 traits_and_interfaces[i] = trait;
3073 if (trait) {
3074 UPDATE_IS_CACHEABLE(trait);
3075 }
3076 }
3077 }
3078
3079 if (ce->num_interfaces) {
3080 for (i = 0; i < ce->num_interfaces; i++) {
3081 zend_class_entry *iface = zend_fetch_class_by_name(
3082 ce->interface_names[i].name, ce->interface_names[i].lc_name,
3083 ZEND_FETCH_CLASS_INTERFACE |
3084 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3085 if (!iface) {
3086 check_unrecoverable_load_failure(ce);
3087 free_alloca(traits_and_interfaces, use_heap);
3088 return NULL;
3089 }
3090 traits_and_interfaces[ce->num_traits + i] = iface;
3091 if (iface) {
3092 UPDATE_IS_CACHEABLE(iface);
3093 }
3094 }
3095 }
3096
3097 #ifndef ZEND_WIN32
3098 if (ce->ce_flags & ZEND_ACC_ENUM) {
3099 /* We will add internal methods. */
3100 is_cacheable = false;
3101 }
3102 #endif
3103
3104 bool orig_record_errors = EG(record_errors);
3105
3106 if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3107 if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3108 zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3109 if (ret) {
3110 if (traits_and_interfaces) {
3111 free_alloca(traits_and_interfaces, use_heap);
3112 }
3113 zv = zend_hash_find_known_hash(CG(class_table), key);
3114 Z_CE_P(zv) = ret;
3115 return ret;
3116 }
3117
3118 /* Make sure warnings (such as deprecations) thrown during inheritance
3119 * will be recorded in the inheritance cache. */
3120 zend_begin_record_errors();
3121 } else {
3122 is_cacheable = 0;
3123 }
3124 proto = ce;
3125 }
3126
3127 zend_try {
3128 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3129 /* Lazy class loading */
3130 ce = zend_lazy_class_load(ce);
3131 zv = zend_hash_find_known_hash(CG(class_table), key);
3132 Z_CE_P(zv) = ce;
3133 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3134 /* Lazy class loading */
3135 ce = zend_lazy_class_load(ce);
3136 ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3137 zv = zend_hash_find_known_hash(CG(class_table), key);
3138 Z_CE_P(zv) = ce;
3139 }
3140
3141 if (CG(unlinked_uses)) {
3142 zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3143 }
3144
3145 orig_linking_class = CG(current_linking_class);
3146 CG(current_linking_class) = is_cacheable ? ce : NULL;
3147
3148 if (ce->ce_flags & ZEND_ACC_ENUM) {
3149 /* Only register builtin enum methods during inheritance to avoid persisting them in
3150 * opcache. */
3151 zend_enum_register_funcs(ce);
3152 }
3153
3154 if (parent) {
3155 if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3156 add_dependency_obligation(ce, parent);
3157 }
3158 zend_do_inheritance(ce, parent);
3159 }
3160 if (ce->num_traits) {
3161 zend_do_bind_traits(ce, traits_and_interfaces);
3162 }
3163 if (ce->num_interfaces) {
3164 /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3165 uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3166 zend_class_entry **interfaces = emalloc(
3167 sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3168
3169 if (num_parent_interfaces) {
3170 memcpy(interfaces, parent->interfaces,
3171 sizeof(zend_class_entry *) * num_parent_interfaces);
3172 }
3173 memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3174 sizeof(zend_class_entry *) * ce->num_interfaces);
3175
3176 zend_do_implement_interfaces(ce, interfaces);
3177 } else if (parent && parent->num_interfaces) {
3178 zend_do_inherit_interfaces(ce, parent);
3179 }
3180 if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3181 && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3182 ) {
3183 zend_verify_abstract_class(ce);
3184 }
3185 if (ce->ce_flags & ZEND_ACC_ENUM) {
3186 zend_verify_enum(ce);
3187 }
3188
3189 /* Normally Stringable is added during compilation. However, if it is imported from a trait,
3190 * we need to explicitly add the interface here. */
3191 if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3192 && !zend_class_implements_interface(ce, zend_ce_stringable)) {
3193 ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
3194 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
3195 ce->num_interfaces++;
3196 ce->interfaces = perealloc(ce->interfaces,
3197 sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
3198 ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
3199 do_interface_implementation(ce, zend_ce_stringable);
3200 }
3201
3202 zend_build_properties_info_table(ce);
3203 } zend_catch {
3204 /* Do not leak recorded errors to the next linked class. */
3205 if (!orig_record_errors) {
3206 EG(record_errors) = false;
3207 zend_free_recorded_errors();
3208 }
3209 zend_bailout();
3210 } zend_end_try();
3211
3212 EG(record_errors) = orig_record_errors;
3213
3214 if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3215 zend_inheritance_check_override(ce);
3216 ce->ce_flags |= ZEND_ACC_LINKED;
3217 } else {
3218 ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
3219 if (CG(current_linking_class)) {
3220 ce->ce_flags |= ZEND_ACC_CACHEABLE;
3221 }
3222 load_delayed_classes(ce);
3223 if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3224 resolve_delayed_variance_obligations(ce);
3225 }
3226 if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3227 ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3228 } else {
3229 CG(current_linking_class) = NULL;
3230 }
3231 }
3232
3233 if (!CG(current_linking_class)) {
3234 is_cacheable = 0;
3235 }
3236 CG(current_linking_class) = orig_linking_class;
3237
3238 if (is_cacheable) {
3239 HashTable *ht = (HashTable*)ce->inheritance_cache;
3240 zend_class_entry *new_ce;
3241
3242 ce->inheritance_cache = NULL;
3243 new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3244 if (new_ce) {
3245 zv = zend_hash_find_known_hash(CG(class_table), key);
3246 ce = new_ce;
3247 Z_CE_P(zv) = ce;
3248 }
3249 if (ht) {
3250 zend_hash_destroy(ht);
3251 FREE_HASHTABLE(ht);
3252 }
3253 }
3254
3255 if (!orig_record_errors) {
3256 zend_free_recorded_errors();
3257 }
3258 if (traits_and_interfaces) {
3259 free_alloca(traits_and_interfaces, use_heap);
3260 }
3261
3262 if (ZSTR_HAS_CE_CACHE(ce->name)) {
3263 ZSTR_SET_CE_CACHE(ce->name, ce);
3264 }
3265
3266 return ce;
3267 }
3268 /* }}} */
3269
3270 /* 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)3271 static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
3272 {
3273 zend_string *key;
3274 zend_function *parent_func;
3275 zend_property_info *parent_info;
3276 zend_class_constant *parent_const;
3277 inheritance_status overall_status = INHERITANCE_SUCCESS;
3278
3279 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3280 zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3281 if (zv) {
3282 zend_function *child_func = Z_FUNC_P(zv);
3283 inheritance_status status =
3284 do_inheritance_check_on_method(
3285 child_func, child_func->common.scope,
3286 parent_func, parent_func->common.scope,
3287 ce, NULL,
3288 ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3289 if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3290 overall_status = INHERITANCE_WARNING;
3291 } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3292 return status;
3293 }
3294 }
3295 } ZEND_HASH_FOREACH_END();
3296
3297 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3298 zval *zv;
3299 if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3300 continue;
3301 }
3302
3303 zv = zend_hash_find_known_hash(&ce->properties_info, key);
3304 if (zv) {
3305 zend_property_info *child_info = Z_PTR_P(zv);
3306 if (ZEND_TYPE_IS_SET(child_info->type)) {
3307 inheritance_status status = property_types_compatible(parent_info, child_info);
3308 ZEND_ASSERT(status != INHERITANCE_WARNING);
3309 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3310 return status;
3311 }
3312 }
3313 }
3314 } ZEND_HASH_FOREACH_END();
3315
3316 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3317 zval *zv;
3318 if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3319 continue;
3320 }
3321
3322 zv = zend_hash_find_known_hash(&ce->constants_table, key);
3323 if (zv) {
3324 zend_class_constant *child_const = Z_PTR_P(zv);
3325 if (ZEND_TYPE_IS_SET(child_const->type)) {
3326 inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3327 ZEND_ASSERT(status != INHERITANCE_WARNING);
3328 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3329 return status;
3330 }
3331 }
3332 }
3333 } ZEND_HASH_FOREACH_END();
3334
3335 return overall_status;
3336 }
3337 /* }}} */
3338
register_early_bound_ce(zval * delayed_early_binding,zend_string * lcname,zend_class_entry * ce)3339 static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3340 if (delayed_early_binding) {
3341 if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3342 if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3343 Z_CE_P(delayed_early_binding) = ce;
3344 return true;
3345 }
3346 } else {
3347 /* If preloading is used, don't replace the existing bucket, add a new one. */
3348 if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3349 return true;
3350 }
3351 }
3352 zend_class_entry *old_ce = zend_hash_find_ptr(EG(class_table), lcname);
3353 ZEND_ASSERT(old_ce);
3354 zend_class_redeclaration_error(E_COMPILE_ERROR, old_ce);
3355 return false;
3356 }
3357 if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3358 return true;
3359 }
3360 return false;
3361 }
3362
zend_try_early_bind(zend_class_entry * ce,zend_class_entry * parent_ce,zend_string * lcname,zval * delayed_early_binding)3363 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) /* {{{ */
3364 {
3365 inheritance_status status;
3366 zend_class_entry *proto = NULL;
3367 zend_class_entry *orig_linking_class;
3368
3369 if (ce->ce_flags & ZEND_ACC_LINKED) {
3370 ZEND_ASSERT(ce->parent == NULL);
3371 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3372 return NULL;
3373 }
3374 zend_observer_class_linked_notify(ce, lcname);
3375 return ce;
3376 }
3377
3378 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3379 UPDATE_IS_CACHEABLE(parent_ce);
3380 if (is_cacheable) {
3381 if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3382 zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3383 if (ret) {
3384 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
3385 return NULL;
3386 }
3387 zend_observer_class_linked_notify(ret, lcname);
3388 return ret;
3389 }
3390 } else {
3391 is_cacheable = 0;
3392 }
3393 proto = ce;
3394 }
3395
3396 orig_linking_class = CG(current_linking_class);
3397 CG(current_linking_class) = NULL;
3398 status = zend_can_early_bind(ce, parent_ce);
3399 CG(current_linking_class) = orig_linking_class;
3400 if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3401 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3402 /* Lazy class loading */
3403 ce = zend_lazy_class_load(ce);
3404 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3405 /* Lazy class loading */
3406 ce = zend_lazy_class_load(ce);
3407 ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3408 }
3409
3410 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3411 return NULL;
3412 }
3413
3414 orig_linking_class = CG(current_linking_class);
3415 CG(current_linking_class) = is_cacheable ? ce : NULL;
3416
3417 zend_try{
3418 if (is_cacheable) {
3419 zend_begin_record_errors();
3420 }
3421
3422 zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3423 if (parent_ce && parent_ce->num_interfaces) {
3424 zend_do_inherit_interfaces(ce, parent_ce);
3425 }
3426 zend_build_properties_info_table(ce);
3427 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) {
3428 zend_verify_abstract_class(ce);
3429 }
3430 zend_inheritance_check_override(ce);
3431 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3432 ce->ce_flags |= ZEND_ACC_LINKED;
3433
3434 CG(current_linking_class) = orig_linking_class;
3435 } zend_catch {
3436 EG(record_errors) = false;
3437 zend_free_recorded_errors();
3438 zend_bailout();
3439 } zend_end_try();
3440
3441 EG(record_errors) = false;
3442
3443 if (is_cacheable) {
3444 HashTable *ht = (HashTable*)ce->inheritance_cache;
3445 zend_class_entry *new_ce;
3446
3447 ce->inheritance_cache = NULL;
3448 new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3449 if (new_ce) {
3450 zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3451 ce = new_ce;
3452 Z_CE_P(zv) = ce;
3453 }
3454 if (ht) {
3455 zend_hash_destroy(ht);
3456 FREE_HASHTABLE(ht);
3457 }
3458 }
3459
3460 if (ZSTR_HAS_CE_CACHE(ce->name)) {
3461 ZSTR_SET_CE_CACHE(ce->name, ce);
3462 }
3463 zend_observer_class_linked_notify(ce, lcname);
3464
3465 return ce;
3466 }
3467 return NULL;
3468 }
3469 /* }}} */
3470