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