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