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