xref: /php-src/Zend/zend_inheritance.c (revision e1221523)
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|ZEND_ACC_ENUM))) {
1761 		/* Class must not extend an enum (GH-16315); check enums first since
1762 		 * enums are implemented as final classes */
1763 		if (parent_ce->ce_flags & ZEND_ACC_ENUM) {
1764 			zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend enum %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1765 		}
1766 		/* Class must not extend a final class */
1767 		if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1768 			zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1769 		}
1770 
1771 		/* Class declaration must not extend traits or interfaces */
1772 		if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1773 			zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1774 				ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1775 			);
1776 		}
1777 	}
1778 
1779 	if (UNEXPECTED((ce->ce_flags & ZEND_ACC_READONLY_CLASS) != (parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS))) {
1780 		zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1781 			ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1782 			parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1783 		);
1784 	}
1785 
1786 	if (ce->parent_name) {
1787 		zend_string_release_ex(ce->parent_name, 0);
1788 	}
1789 	ce->parent = parent_ce;
1790 	ce->default_object_handlers = parent_ce->default_object_handlers;
1791 	ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1792 
1793 	/* Inherit properties */
1794 	if (parent_ce->default_properties_count) {
1795 		zval *src, *dst, *end;
1796 
1797 		if (ce->default_properties_count) {
1798 			zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1799 			src = ce->default_properties_table + ce->default_properties_count;
1800 			end = table + parent_ce->default_properties_count;
1801 			dst = end + ce->default_properties_count;
1802 			ce->default_properties_table = table;
1803 			do {
1804 				dst--;
1805 				src--;
1806 				ZVAL_COPY_VALUE_PROP(dst, src);
1807 			} while (dst != end);
1808 			pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1809 			end = ce->default_properties_table;
1810 		} else {
1811 			end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1812 			dst = end + parent_ce->default_properties_count;
1813 			ce->default_properties_table = end;
1814 		}
1815 		src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1816 		if (UNEXPECTED(parent_ce->type != ce->type)) {
1817 			/* User class extends internal */
1818 			do {
1819 				dst--;
1820 				src--;
1821 				/* We don't have to account for refcounting because
1822 				 * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1823 				ZEND_ASSERT(!Z_REFCOUNTED_P(src));
1824 				ZVAL_COPY_VALUE_PROP(dst, src);
1825 				if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1826 					ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1827 					ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1828 				}
1829 				continue;
1830 			} while (dst != end);
1831 		} else {
1832 			do {
1833 				dst--;
1834 				src--;
1835 				ZVAL_COPY_PROP(dst, src);
1836 				if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1837 					ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1838 					ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
1839 				}
1840 				continue;
1841 			} while (dst != end);
1842 		}
1843 		ce->default_properties_count += parent_ce->default_properties_count;
1844 	}
1845 
1846 	if (parent_ce->default_static_members_count) {
1847 		zval *src, *dst, *end;
1848 
1849 		if (ce->default_static_members_count) {
1850 			zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1851 			src = ce->default_static_members_table + ce->default_static_members_count;
1852 			end = table + parent_ce->default_static_members_count;
1853 			dst = end + ce->default_static_members_count;
1854 			ce->default_static_members_table = table;
1855 			do {
1856 				dst--;
1857 				src--;
1858 				ZVAL_COPY_VALUE(dst, src);
1859 			} while (dst != end);
1860 			pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1861 			end = ce->default_static_members_table;
1862 		} else {
1863 			end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1864 			dst = end + parent_ce->default_static_members_count;
1865 			ce->default_static_members_table = end;
1866 		}
1867 		src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1868 		do {
1869 			dst--;
1870 			src--;
1871 			if (Z_TYPE_P(src) == IS_INDIRECT) {
1872 				ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1873 			} else {
1874 				ZVAL_INDIRECT(dst, src);
1875 			}
1876 			if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1877 				ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1878 				ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
1879 			}
1880 		} while (dst != end);
1881 		ce->default_static_members_count += parent_ce->default_static_members_count;
1882 		if (!ZEND_MAP_PTR(ce->static_members_table)) {
1883 			if (ce->type == ZEND_INTERNAL_CLASS &&
1884 					ce->info.internal.module->type == MODULE_PERSISTENT) {
1885 				ZEND_MAP_PTR_NEW(ce->static_members_table);
1886 			}
1887 		}
1888 	}
1889 
1890 	ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1891 		if (property_info->ce == ce) {
1892 			if (property_info->flags & ZEND_ACC_STATIC) {
1893 				property_info->offset += parent_ce->default_static_members_count;
1894 			} else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1895 				property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1896 			}
1897 		}
1898 	} ZEND_HASH_FOREACH_END();
1899 
1900 	if (zend_hash_num_elements(&parent_ce->properties_info)) {
1901 		zend_hash_extend(&ce->properties_info,
1902 			zend_hash_num_elements(&ce->properties_info) +
1903 			zend_hash_num_elements(&parent_ce->properties_info), 0);
1904 
1905 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1906 			do_inherit_property(property_info, key, ce);
1907 		} ZEND_HASH_FOREACH_END();
1908 	}
1909 
1910 	if (ce->num_hooked_props) {
1911 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, property_info) {
1912 			if (property_info->ce == ce && property_info->hooks) {
1913 				zend_verify_hooked_property(ce, property_info, key);
1914 			}
1915 		} ZEND_HASH_FOREACH_END();
1916 	}
1917 
1918 	if (zend_hash_num_elements(&parent_ce->constants_table)) {
1919 		zend_class_constant *c;
1920 
1921 		zend_hash_extend(&ce->constants_table,
1922 			zend_hash_num_elements(&ce->constants_table) +
1923 			zend_hash_num_elements(&parent_ce->constants_table), 0);
1924 
1925 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
1926 			do_inherit_class_constant(key, c, ce);
1927 		} ZEND_HASH_FOREACH_END();
1928 	}
1929 
1930 	if (zend_hash_num_elements(&parent_ce->function_table)) {
1931 		zend_hash_extend(&ce->function_table,
1932 			zend_hash_num_elements(&ce->function_table) +
1933 			zend_hash_num_elements(&parent_ce->function_table), 0);
1934 		uint32_t flags =
1935 			ZEND_INHERITANCE_LAZY_CHILD_CLONE |
1936 			ZEND_INHERITANCE_SET_CHILD_CHANGED |
1937 			ZEND_INHERITANCE_SET_CHILD_PROTO |
1938 			ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
1939 
1940 		if (!checked) {
1941 			flags |= ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
1942 		}
1943 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1944 			do_inherit_method(key, func, ce, 0, flags);
1945 		} ZEND_HASH_FOREACH_END();
1946 	}
1947 
1948 	do_inherit_parent_constructor(ce);
1949 
1950 	if (ce->type == ZEND_INTERNAL_CLASS) {
1951 		if (parent_ce->num_interfaces) {
1952 			zend_do_inherit_interfaces(ce, parent_ce);
1953 		}
1954 
1955 		if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1956 			ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1957 		}
1958 	}
1959 	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);
1960 }
1961 /* }}} */
1962 
check_trait_property_or_constant_value_compatibility(zend_class_entry * ce,zval * op1,zval * op2)1963 static zend_always_inline bool check_trait_property_or_constant_value_compatibility(zend_class_entry *ce, zval *op1, zval *op2) /* {{{ */
1964 {
1965 	bool is_compatible;
1966 	zval op1_tmp, op2_tmp;
1967 
1968 	/* if any of the values is a constant, we try to resolve it */
1969 	if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
1970 		ZVAL_COPY_OR_DUP(&op1_tmp, op1);
1971 		if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
1972 			zval_ptr_dtor(&op1_tmp);
1973 			return false;
1974 		}
1975 		op1 = &op1_tmp;
1976 	}
1977 	if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
1978 		ZVAL_COPY_OR_DUP(&op2_tmp, op2);
1979 		if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
1980 			zval_ptr_dtor(&op2_tmp);
1981 			return false;
1982 		}
1983 		op2 = &op2_tmp;
1984 	}
1985 
1986 	is_compatible = fast_is_identical_function(op1, op2);
1987 
1988 	if (op1 == &op1_tmp) {
1989 		zval_ptr_dtor_nogc(&op1_tmp);
1990 	}
1991 	if (op2 == &op2_tmp) {
1992 		zval_ptr_dtor_nogc(&op2_tmp);
1993 	}
1994 
1995 	return is_compatible;
1996 }
1997 /* }}} */
1998 
1999 /** @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)2000 static bool do_inherit_constant_check(
2001 	zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name
2002 ) {
2003 	zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2004 	if (zv == NULL) {
2005 		return true;
2006 	}
2007 
2008 	zend_class_constant *child_constant = Z_PTR_P(zv);
2009 	if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
2010 		zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
2011 			ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2012 			ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
2013 		);
2014 	}
2015 
2016 	if (child_constant->ce != parent_constant->ce && child_constant->ce != ce) {
2017 		zend_error_noreturn(E_COMPILE_ERROR,
2018 			"%s %s inherits both %s::%s and %s::%s, which is ambiguous",
2019 			zend_get_object_type_uc(ce),
2020 			ZSTR_VAL(ce->name),
2021 			ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2022 			ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
2023 	}
2024 
2025 	if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(child_constant) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PPP_MASK))) {
2026 		zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in %s %s)%s",
2027 			ZSTR_VAL(ce->name), ZSTR_VAL(name),
2028 			zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_constant)),
2029 			zend_get_object_type(parent_constant->ce),
2030 			ZSTR_VAL(parent_constant->ce->name),
2031 			(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PUBLIC) ? "" : " or weaker"
2032 		);
2033 	}
2034 
2035 	if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
2036 		inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
2037 		if (status == INHERITANCE_ERROR) {
2038 			emit_incompatible_class_constant_error(child_constant, parent_constant, name);
2039 		} else if (status == INHERITANCE_UNRESOLVED) {
2040 			add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
2041 		}
2042 	}
2043 
2044 	return false;
2045 }
2046 /* }}} */
2047 
do_inherit_iface_constant(zend_string * name,zend_class_constant * c,zend_class_entry * ce,zend_class_entry * iface)2048 static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2049 {
2050 	if (do_inherit_constant_check(ce, c, name)) {
2051 		zend_class_constant *ct;
2052 		if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2053 			ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2054 			ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2055 			if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
2056 				ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2057 				memcpy(ct, c, sizeof(zend_class_constant));
2058 				c = ct;
2059 				Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED;
2060 			}
2061 		}
2062 		if (ce->type & ZEND_INTERNAL_CLASS) {
2063 			ct = pemalloc(sizeof(zend_class_constant), 1);
2064 			memcpy(ct, c, sizeof(zend_class_constant));
2065 			c = ct;
2066 		}
2067 		zend_hash_update_ptr(&ce->constants_table, name, c);
2068 	}
2069 }
2070 /* }}} */
2071 
do_interface_implementation(zend_class_entry * ce,zend_class_entry * iface)2072 static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2073 {
2074 	zend_function *func;
2075 	zend_string *key;
2076 	zend_class_constant *c;
2077 	uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2078 
2079 	if (!(ce->ce_flags & ZEND_ACC_INTERFACE)) {
2080 		/* We are not setting the prototype of overridden interface methods because of abstract
2081 		 * constructors. See Zend/tests/interface_constructor_prototype_001.phpt. */
2082 		flags |=
2083 			ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2084 			ZEND_INHERITANCE_SET_CHILD_PROTO |
2085 			ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2086 	} else {
2087 		flags |=
2088 			ZEND_INHERITANCE_LAZY_CHILD_CLONE |
2089 			ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2090 	}
2091 
2092 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2093 		do_inherit_iface_constant(key, c, ce, iface);
2094 	} ZEND_HASH_FOREACH_END();
2095 
2096 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
2097 		do_inherit_method(key, func, ce, 1, flags);
2098 	} ZEND_HASH_FOREACH_END();
2099 
2100 	zend_hash_extend(&ce->properties_info,
2101 		zend_hash_num_elements(&ce->properties_info) +
2102 		zend_hash_num_elements(&iface->properties_info), 0);
2103 
2104 	zend_property_info *prop;
2105 	ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->properties_info, key, prop) {
2106 		do_inherit_property(prop, key, ce);
2107 	} ZEND_HASH_FOREACH_END();
2108 
2109 	do_implement_interface(ce, iface);
2110 	if (iface->num_interfaces) {
2111 		zend_do_inherit_interfaces(ce, iface);
2112 	}
2113 }
2114 /* }}} */
2115 
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)2116 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2117 {
2118 	uint32_t i, ignore = 0;
2119 	uint32_t current_iface_num = ce->num_interfaces;
2120 	uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
2121 	zend_string *key;
2122 	zend_class_constant *c;
2123 
2124 	ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2125 
2126 	for (i = 0; i < ce->num_interfaces; i++) {
2127 		if (ce->interfaces[i] == NULL) {
2128 			memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
2129 			i--;
2130 		} else if (ce->interfaces[i] == iface) {
2131 			if (EXPECTED(i < parent_iface_num)) {
2132 				ignore = 1;
2133 			} else {
2134 				zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2135 			}
2136 		}
2137 	}
2138 	if (ignore) {
2139 		/* Check for attempt to redeclare interface constants */
2140 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2141 			do_inherit_constant_check(ce, c, key);
2142 		} ZEND_HASH_FOREACH_END();
2143 	} else {
2144 		if (ce->num_interfaces >= current_iface_num) {
2145 			if (ce->type == ZEND_INTERNAL_CLASS) {
2146 				ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2147 			} else {
2148 				ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2149 			}
2150 		}
2151 		ce->interfaces[ce->num_interfaces++] = iface;
2152 
2153 		do_interface_implementation(ce, iface);
2154 	}
2155 }
2156 /* }}} */
2157 
zend_do_implement_interfaces(zend_class_entry * ce,zend_class_entry ** interfaces)2158 static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
2159 {
2160 	zend_class_entry *iface;
2161 	uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2162 	uint32_t num_interfaces = num_parent_interfaces;
2163 	zend_string *key;
2164 	zend_class_constant *c;
2165 	uint32_t i, j;
2166 
2167 	for (i = 0; i < ce->num_interfaces; i++) {
2168 		iface = interfaces[num_parent_interfaces + i];
2169 		if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2170 			add_dependency_obligation(ce, iface);
2171 		}
2172 		if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
2173 			efree(interfaces);
2174 			zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2175 			return;
2176 		}
2177 		for (j = 0; j < num_interfaces; j++) {
2178 			if (interfaces[j] == iface) {
2179 				if (j >= num_parent_interfaces) {
2180 					efree(interfaces);
2181 					zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
2182 						zend_get_object_type_uc(ce),
2183 						ZSTR_VAL(ce->name),
2184 						ZSTR_VAL(iface->name));
2185 					return;
2186 				}
2187 				/* skip duplications */
2188 				ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
2189 					do_inherit_constant_check(ce, c, key);
2190 				} ZEND_HASH_FOREACH_END();
2191 
2192 				iface = NULL;
2193 				break;
2194 			}
2195 		}
2196 		if (iface) {
2197 			interfaces[num_interfaces] = iface;
2198 			num_interfaces++;
2199 		}
2200 	}
2201 
2202 	if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2203 		for (i = 0; i < ce->num_interfaces; i++) {
2204 			zend_string_release_ex(ce->interface_names[i].name, 0);
2205 			zend_string_release_ex(ce->interface_names[i].lc_name, 0);
2206 		}
2207 		efree(ce->interface_names);
2208 	}
2209 
2210 	ce->num_interfaces = num_interfaces;
2211 	ce->interfaces = interfaces;
2212 	ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2213 
2214 	for (i = 0; i < num_parent_interfaces; i++) {
2215 		do_implement_interface(ce, ce->interfaces[i]);
2216 	}
2217 	/* Note that new interfaces can be added during this loop due to interface inheritance.
2218 	 * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */
2219 	for (; i < num_interfaces; i++) {
2220 		do_interface_implementation(ce, ce->interfaces[i]);
2221 	}
2222 }
2223 /* }}} */
2224 
2225 
zend_inheritance_check_override(zend_class_entry * ce)2226 void zend_inheritance_check_override(zend_class_entry *ce)
2227 {
2228 	zend_function *f;
2229 
2230 	if (ce->ce_flags & ZEND_ACC_TRAIT) {
2231 		return;
2232 	}
2233 
2234 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, f) {
2235 		if (f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2236 			ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2237 
2238 			zend_error_at_noreturn(
2239 				E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2240 				"%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2241 				ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2242 		}
2243 	} ZEND_HASH_FOREACH_END();
2244 
2245 	if (ce->num_hooked_props) {
2246 		zend_property_info *prop;
2247 		ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
2248 			if (!prop->hooks) {
2249 				continue;
2250 			}
2251 			for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2252 				f = prop->hooks[i];
2253 				if (f && f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2254 					ZEND_ASSERT(f->type != ZEND_INTERNAL_FUNCTION);
2255 
2256 					zend_error_at_noreturn(
2257 						E_COMPILE_ERROR, f->op_array.filename, f->op_array.line_start,
2258 						"%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2259 						ZEND_FN_SCOPE_NAME(f), ZSTR_VAL(f->common.function_name));
2260 				}
2261 			}
2262 		} ZEND_HASH_FOREACH_END();
2263 	}
2264 }
2265 
2266 
fixup_trait_scope(const zend_function * fn,zend_class_entry * ce)2267 static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
2268 {
2269 	/* self in trait methods should be resolved to the using class, not the trait. */
2270 	return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
2271 }
2272 
zend_add_trait_method(zend_class_entry * ce,zend_string * name,zend_string * key,zend_function * fn)2273 static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
2274 {
2275 	zend_function *existing_fn = NULL;
2276 	zend_function *new_fn;
2277 	bool check_inheritance = false;
2278 
2279 	if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
2280 		/* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
2281 		 * of where it is coming from there is no conflict and we do not need to add it again */
2282 		if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
2283 			(existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
2284 			(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2285 			return;
2286 		}
2287 
2288 		/* Abstract method signatures from the trait must be satisfied. */
2289 		if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2290 			/* "abstract private" methods in traits were not available prior to PHP 8.
2291 			 * As such, "abstract protected" was sometimes used to indicate trait requirements,
2292 			 * even though the "implementing" method was private. Do not check visibility
2293 			 * requirements to maintain backwards-compatibility with such usage.
2294 			 */
2295 			do_inheritance_check_on_method(
2296 				existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
2297 				ce, NULL, ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_RESET_CHILD_OVERRIDE);
2298 			return;
2299 		}
2300 
2301 		if (existing_fn->common.scope == ce) {
2302 			/* members from the current class override trait methods */
2303 			return;
2304 		} else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
2305 				&& !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
2306 			/* two traits can't define the same non-abstract method */
2307 			zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
2308 				ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
2309 				ZSTR_VAL(ce->name), ZSTR_VAL(name),
2310 				ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
2311 		} else {
2312 			check_inheritance = true;
2313 		}
2314 	}
2315 
2316 	if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
2317 		new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
2318 		memcpy(new_fn, fn, sizeof(zend_internal_function));
2319 		new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
2320 	} else {
2321 		new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2322 		memcpy(new_fn, fn, sizeof(zend_op_array));
2323 		new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2324 	}
2325 	new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2326 
2327 	/* Reassign method name, in case it is an alias. */
2328 	new_fn->common.function_name = name;
2329 	function_add_ref(new_fn);
2330 	fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2331 	zend_add_magic_method(ce, fn, key);
2332 
2333 	if (check_inheritance) {
2334 		/* Inherited members are overridden by members inserted by traits.
2335 		 * Check whether the trait method fulfills the inheritance requirements. */
2336 		uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;
2337 		if (!(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2338 			flags |= ZEND_INHERITANCE_SET_CHILD_CHANGED |ZEND_INHERITANCE_SET_CHILD_PROTO |
2339 				ZEND_INHERITANCE_RESET_CHILD_OVERRIDE;
2340 		}
2341 		do_inheritance_check_on_method(
2342 			fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce),
2343 			ce, NULL, flags);
2344 	}
2345 }
2346 /* }}} */
2347 
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce)2348 static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2349 {
2350 	if (fn->common.scope->ce_flags & ZEND_ACC_TRAIT) {
2351 
2352 		fn->common.scope = ce;
2353 
2354 		if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2355 			ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2356 		}
2357 		if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
2358 			ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
2359 		}
2360 	}
2361 }
2362 /* }}} */
2363 
zend_traits_check_private_final_inheritance(uint32_t original_fn_flags,zend_function * fn_copy,zend_string * name)2364 static void zend_traits_check_private_final_inheritance(uint32_t original_fn_flags, zend_function *fn_copy, zend_string *name)
2365 {
2366 	/* If the function was originally already private+final, then it will have already been warned about.
2367 	 * If the function became private+final only after applying modifiers, we need to emit the same warning. */
2368 	if ((original_fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) != (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2369 		&& (fn_copy->common.fn_flags & (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)) == (ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
2370 		&& !zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2371 		zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2372 	}
2373 }
2374 
zend_traits_copy_functions(zend_string * fnname,zend_function * fn,zend_class_entry * ce,HashTable * exclude_table,zend_class_entry ** aliases)2375 static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
2376 {
2377 	zend_trait_alias  *alias, **alias_ptr;
2378 	zend_string       *lcname;
2379 	zend_function      fn_copy;
2380 	int                i;
2381 
2382 	/* apply aliases which are qualified with a class name, there should not be any ambiguity */
2383 	if (ce->trait_aliases) {
2384 		alias_ptr = ce->trait_aliases;
2385 		alias = *alias_ptr;
2386 		i = 0;
2387 		while (alias) {
2388 			/* Scope unset or equal to the function we compare to, and the alias applies to fn */
2389 			if (alias->alias != NULL
2390 				&& fn->common.scope == aliases[i]
2391 				&& zend_string_equals_ci(alias->trait_method.method_name, fnname)
2392 			) {
2393 				fn_copy = *fn;
2394 				if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2395 					fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2396 				} else {
2397 					fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2398 				}
2399 
2400 				zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2401 
2402 				lcname = zend_string_tolower(alias->alias);
2403 				zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2404 				zend_string_release_ex(lcname, 0);
2405 			}
2406 			alias_ptr++;
2407 			alias = *alias_ptr;
2408 			i++;
2409 		}
2410 	}
2411 
2412 	if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2413 		/* is not in hashtable, thus, function is not to be excluded */
2414 		memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
2415 
2416 		/* apply aliases which have not alias name, just setting visibility */
2417 		if (ce->trait_aliases) {
2418 			alias_ptr = ce->trait_aliases;
2419 			alias = *alias_ptr;
2420 			i = 0;
2421 			while (alias) {
2422 				/* Scope unset or equal to the function we compare to, and the alias applies to fn */
2423 				if (alias->alias == NULL && alias->modifiers != 0
2424 					&& fn->common.scope == aliases[i]
2425 					&& zend_string_equals_ci(alias->trait_method.method_name, fnname)
2426 				) {
2427 					if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2428 						fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2429 					} else {
2430 						fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2431 					}
2432 				}
2433 				alias_ptr++;
2434 				alias = *alias_ptr;
2435 				i++;
2436 			}
2437 		}
2438 
2439 		zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2440 
2441 		zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2442 	}
2443 }
2444 /* }}} */
2445 
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait,zend_class_entry ** traits)2446 static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait, zend_class_entry **traits) /* {{{ */
2447 {
2448 	uint32_t i;
2449 
2450 	if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2451 		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));
2452 		return 0;
2453 	}
2454 
2455 	for (i = 0; i < ce->num_traits; i++) {
2456 		if (traits[i] == trait) {
2457 			return i;
2458 		}
2459 	}
2460 	zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
2461 	return 0;
2462 }
2463 /* }}} */
2464 
zend_traits_init_trait_structures(zend_class_entry * ce,zend_class_entry ** traits,HashTable *** exclude_tables_ptr,zend_class_entry *** aliases_ptr)2465 static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
2466 {
2467 	size_t i, j = 0;
2468 	zend_trait_precedence **precedences;
2469 	zend_trait_precedence *cur_precedence;
2470 	zend_trait_method_reference *cur_method_ref;
2471 	zend_string *lc_trait_name;
2472 	zend_string *lcname;
2473 	HashTable **exclude_tables = NULL;
2474 	zend_class_entry **aliases = NULL;
2475 	zend_class_entry *trait;
2476 
2477 	/* resolve class references */
2478 	if (ce->trait_precedences) {
2479 		exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2480 		i = 0;
2481 		precedences = ce->trait_precedences;
2482 		ce->trait_precedences = NULL;
2483 		while ((cur_precedence = precedences[i])) {
2484 			/** Resolve classes for all precedence operations. */
2485 			cur_method_ref = &cur_precedence->trait_method;
2486 			lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2487 			trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2488 			zend_string_release_ex(lc_trait_name, 0);
2489 			if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2490 				zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2491 			}
2492 			zend_check_trait_usage(ce, trait, traits);
2493 
2494 			/** Ensure that the preferred method is actually available. */
2495 			lcname = zend_string_tolower(cur_method_ref->method_name);
2496 			if (!zend_hash_exists(&trait->function_table, lcname)) {
2497 				zend_error_noreturn(E_COMPILE_ERROR,
2498 						   "A precedence rule was defined for %s::%s but this method does not exist",
2499 						   ZSTR_VAL(trait->name),
2500 						   ZSTR_VAL(cur_method_ref->method_name));
2501 			}
2502 
2503 			/** With the other traits, we are more permissive.
2504 				We do not give errors for those. This allows to be more
2505 				defensive in such definitions.
2506 				However, we want to make sure that the insteadof declaration
2507 				is consistent in itself.
2508 			 */
2509 
2510 			for (j = 0; j < cur_precedence->num_excludes; j++) {
2511 				zend_string* class_name = cur_precedence->exclude_class_names[j];
2512 				zend_class_entry *exclude_ce;
2513 				uint32_t trait_num;
2514 
2515 				lc_trait_name = zend_string_tolower(class_name);
2516 				exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2517 				zend_string_release_ex(lc_trait_name, 0);
2518 				if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2519 					zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2520 				}
2521 				trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2522 				if (!exclude_tables[trait_num]) {
2523 					ALLOC_HASHTABLE(exclude_tables[trait_num]);
2524 					zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2525 				}
2526 				if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2527 					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));
2528 				}
2529 
2530 				/* make sure that the trait method is not from a class mentioned in
2531 				 exclude_from_classes, for consistency */
2532 				if (trait == exclude_ce) {
2533 					zend_error_noreturn(E_COMPILE_ERROR,
2534 							   "Inconsistent insteadof definition. "
2535 							   "The method %s is to be used from %s, but %s is also on the exclude list",
2536 							   ZSTR_VAL(cur_method_ref->method_name),
2537 							   ZSTR_VAL(trait->name),
2538 							   ZSTR_VAL(trait->name));
2539 				}
2540 			}
2541 			zend_string_release_ex(lcname, 0);
2542 			i++;
2543 		}
2544 		ce->trait_precedences = precedences;
2545 	}
2546 
2547 	if (ce->trait_aliases) {
2548 		i = 0;
2549 		while (ce->trait_aliases[i]) {
2550 			i++;
2551 		}
2552 		aliases = ecalloc(i, sizeof(zend_class_entry*));
2553 		i = 0;
2554 		while (ce->trait_aliases[i]) {
2555 			zend_trait_alias *cur_alias = ce->trait_aliases[i];
2556 			cur_method_ref = &ce->trait_aliases[i]->trait_method;
2557 			lcname = zend_string_tolower(cur_method_ref->method_name);
2558 			if (cur_method_ref->class_name) {
2559 				/* For all aliases with an explicit class name, resolve the class now. */
2560 				lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2561 				trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2562 				zend_string_release_ex(lc_trait_name, 0);
2563 				if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2564 					zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2565 				}
2566 				zend_check_trait_usage(ce, trait, traits);
2567 				aliases[i] = trait;
2568 
2569 				/* And, ensure that the referenced method is resolvable, too. */
2570 				if (!zend_hash_exists(&trait->function_table, lcname)) {
2571 					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));
2572 				}
2573 			} else {
2574 				/* Find out which trait this method refers to. */
2575 				trait = NULL;
2576 				for (j = 0; j < ce->num_traits; j++) {
2577 					if (traits[j]) {
2578 						if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2579 							if (!trait) {
2580 								trait = traits[j];
2581 								continue;
2582 							}
2583 
2584 							zend_error_noreturn(E_COMPILE_ERROR,
2585 								"An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
2586 								ZSTR_VAL(cur_method_ref->method_name),
2587 								ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2588 								ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2589 								ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2590 						}
2591 					}
2592 				}
2593 
2594 				/* Non-absolute method reference refers to method that does not exist. */
2595 				if (!trait) {
2596 					if (cur_alias->alias) {
2597 						zend_error_noreturn(E_COMPILE_ERROR,
2598 							"An alias (%s) was defined for method %s(), but this method does not exist",
2599 							ZSTR_VAL(cur_alias->alias),
2600 							ZSTR_VAL(cur_alias->trait_method.method_name));
2601 					} else {
2602 						zend_error_noreturn(E_COMPILE_ERROR,
2603 							"The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2604 							ZSTR_VAL(cur_alias->trait_method.method_name));
2605 					}
2606 				}
2607 
2608 				aliases[i] = trait;
2609 			}
2610 			zend_string_release_ex(lcname, 0);
2611 			i++;
2612 		}
2613 	}
2614 
2615 	*exclude_tables_ptr = exclude_tables;
2616 	*aliases_ptr = aliases;
2617 }
2618 /* }}} */
2619 
zend_do_traits_method_binding(zend_class_entry * ce,zend_class_entry ** traits,HashTable ** exclude_tables,zend_class_entry ** aliases)2620 static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
2621 {
2622 	uint32_t i;
2623 	zend_string *key;
2624 	zend_function *fn;
2625 
2626 	if (exclude_tables) {
2627 		for (i = 0; i < ce->num_traits; i++) {
2628 			if (traits[i]) {
2629 				/* copies functions, applies defined aliasing, and excludes unused trait methods */
2630 				ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2631 					zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2632 				} ZEND_HASH_FOREACH_END();
2633 
2634 				if (exclude_tables[i]) {
2635 					zend_hash_destroy(exclude_tables[i]);
2636 					FREE_HASHTABLE(exclude_tables[i]);
2637 					exclude_tables[i] = NULL;
2638 				}
2639 			}
2640 		}
2641 	} else {
2642 		for (i = 0; i < ce->num_traits; i++) {
2643 			if (traits[i]) {
2644 				ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2645 					zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2646 				} ZEND_HASH_FOREACH_END();
2647 			}
2648 		}
2649 	}
2650 
2651 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
2652 		zend_fixup_trait_method(fn, ce);
2653 	} ZEND_HASH_FOREACH_END();
2654 }
2655 /* }}} */
2656 
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)2657 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) /* {{{ */
2658 {
2659 	/* This function is used to show the place of the existing conflicting
2660 	 * definition in error messages when conflicts occur. Since trait constants
2661 	 * are flattened into the constants table of the composing class, and thus
2662 	 * we lose information about which constant was defined in which trait, a
2663 	 * process like this is needed to find the location of the first definition
2664 	 * of the constant from traits.
2665 	 */
2666 	size_t i;
2667 
2668 	if (colliding_ce == ce) {
2669 		for (i = 0; i < current_trait; i++) {
2670 			if (traits[i]
2671 				&& zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2672 				return traits[i];
2673 			}
2674 		}
2675 	}
2676 	/* Traits don't have it, then the composing class (or trait) itself has it. */
2677 	return colliding_ce;
2678 }
2679 /* }}} */
2680 
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)2681 static void emit_incompatible_trait_constant_error(
2682 	const zend_class_entry *ce, const zend_class_constant *existing_constant, const zend_class_constant *trait_constant, zend_string *name,
2683 	zend_class_entry **traits, size_t current_trait
2684 ) {
2685 	zend_error_noreturn(E_COMPILE_ERROR,
2686 		"%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2687 		ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2688 		ZSTR_VAL(trait_constant->ce->name),
2689 		ZSTR_VAL(name),
2690 		ZSTR_VAL(ce->name)
2691 	);
2692 }
2693 
do_trait_constant_check(zend_class_entry * ce,zend_class_constant * trait_constant,zend_string * name,zend_class_entry ** traits,size_t current_trait)2694 static bool do_trait_constant_check(
2695 	zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait
2696 ) {
2697 	uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2698 
2699 	zval *zv = zend_hash_find_known_hash(&ce->constants_table, name);
2700 	if (zv == NULL) {
2701 		/* No existing constant of the same name, so this one can be added */
2702 		return true;
2703 	}
2704 
2705 	zend_class_constant *existing_constant = Z_PTR_P(zv);
2706 
2707 	if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2708 		emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2709 		return false;
2710 	}
2711 
2712 	if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) {
2713 		emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2714 		return false;
2715 	} else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2716 		inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2717 		inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2718 		if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
2719 			emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2720 			return false;
2721 		}
2722 	}
2723 
2724 	if (!check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &existing_constant->value)) {
2725 		/* There is an existing constant of the same name, and it conflicts with the new one, so let's throw a fatal error */
2726 		emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2727 		return false;
2728 	}
2729 
2730 	/* There is an existing constant which is compatible with the new one, so no need to add it */
2731 	return false;
2732 }
2733 
zend_do_traits_constant_binding(zend_class_entry * ce,zend_class_entry ** traits)2734 static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2735 {
2736 	size_t i;
2737 
2738 	for (i = 0; i < ce->num_traits; i++) {
2739 		zend_string *constant_name;
2740 		zend_class_constant *constant;
2741 
2742 		if (!traits[i]) {
2743 			continue;
2744 		}
2745 
2746 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2747 			if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2748 				zend_class_constant *ct = NULL;
2749 
2750 				ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2751 				memcpy(ct, constant, sizeof(zend_class_constant));
2752 				constant = ct;
2753 
2754 				if (Z_TYPE(constant->value) == IS_CONSTANT_AST) {
2755 					ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
2756 					ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
2757 				}
2758 
2759 				/* Unlike interface implementations and class inheritances,
2760 				 * access control of the trait constants is done by the scope
2761 				 * of the composing class. So let's replace the ce here.
2762 				 */
2763 				constant->ce = ce;
2764 
2765 				Z_TRY_ADDREF(constant->value);
2766 				constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2767 				if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2768 					GC_ADDREF(constant->attributes);
2769 				}
2770 
2771 				zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2772 			}
2773 		} ZEND_HASH_FOREACH_END();
2774 	}
2775 }
2776 /* }}} */
2777 
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)2778 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) /* {{{ */
2779 {
2780 	size_t i;
2781 
2782 	if (colliding_ce == ce) {
2783 		for (i = 0; i < current_trait; i++) {
2784 			if (traits[i]
2785 			 && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2786 				return traits[i];
2787 			}
2788 		}
2789 	}
2790 
2791 	return colliding_ce;
2792 }
2793 /* }}} */
2794 
zend_do_traits_property_binding(zend_class_entry * ce,zend_class_entry ** traits)2795 static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2796 {
2797 	size_t i;
2798 	zend_property_info *property_info;
2799 	const zend_property_info *colliding_prop;
2800 	zend_property_info *new_prop;
2801 	zend_string* prop_name;
2802 	zval* prop_value;
2803 	zend_string *doc_comment;
2804 
2805 	/* In the following steps the properties are inserted into the property table
2806 	 * for that, a very strict approach is applied:
2807 	 * - check for compatibility, if not compatible with any property in class -> fatal
2808 	 * - if compatible, then strict notice
2809 	 */
2810 	for (i = 0; i < ce->num_traits; i++) {
2811 		if (!traits[i]) {
2812 			continue;
2813 		}
2814 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2815 			uint32_t flags = property_info->flags;
2816 
2817 			/* next: check for conflicts with current class */
2818 			if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2819 				if ((colliding_prop->flags & ZEND_ACC_PRIVATE) && colliding_prop->ce != ce) {
2820 					zend_hash_del(&ce->properties_info, prop_name);
2821 					flags |= ZEND_ACC_CHANGED;
2822 				} else {
2823 					bool is_compatible = false;
2824 					uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2825 
2826 					if (colliding_prop->hooks || property_info->hooks) {
2827 						zend_error_noreturn(E_COMPILE_ERROR,
2828 							"%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",
2829 							ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2830 							ZSTR_VAL(property_info->ce->name),
2831 							ZSTR_VAL(prop_name),
2832 							ZSTR_VAL(ce->name));
2833 					}
2834 
2835 					if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2836 						verify_property_type_compatibility(property_info, colliding_prop, PROP_INVARIANT, false, false) == INHERITANCE_SUCCESS
2837 					) {
2838 						/* the flags are identical, thus, the properties may be compatible */
2839 						zval *op1, *op2;
2840 
2841 						if (flags & ZEND_ACC_STATIC) {
2842 							op1 = &ce->default_static_members_table[colliding_prop->offset];
2843 							op2 = &traits[i]->default_static_members_table[property_info->offset];
2844 							ZVAL_DEINDIRECT(op1);
2845 							ZVAL_DEINDIRECT(op2);
2846 						} else {
2847 							op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2848 							op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2849 						}
2850 						is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2851 					}
2852 
2853 					if (!is_compatible) {
2854 						zend_error_noreturn(E_COMPILE_ERROR,
2855 								"%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2856 								ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2857 								ZSTR_VAL(property_info->ce->name),
2858 								ZSTR_VAL(prop_name),
2859 								ZSTR_VAL(ce->name));
2860 					}
2861 					if (!(flags & ZEND_ACC_STATIC)) {
2862 						continue;
2863 					}
2864 				}
2865 			}
2866 
2867 			if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS) && !(property_info->flags & ZEND_ACC_READONLY)) {
2868 				zend_error_noreturn(E_COMPILE_ERROR,
2869 					"Readonly class %s cannot use trait with a non-readonly property %s::$%s",
2870 					ZSTR_VAL(ce->name),
2871 					ZSTR_VAL(property_info->ce->name),
2872 					ZSTR_VAL(prop_name)
2873 				);
2874 			}
2875 
2876 			/* property not found, so lets add it */
2877 			zval tmp_prop_value;
2878 			if (!(flags & ZEND_ACC_VIRTUAL)) {
2879 				if (flags & ZEND_ACC_STATIC) {
2880 					prop_value = &traits[i]->default_static_members_table[property_info->offset];
2881 					ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2882 				} else {
2883 					prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2884 				}
2885 				Z_TRY_ADDREF_P(prop_value);
2886 			} else {
2887 				prop_value = &tmp_prop_value;
2888 				ZVAL_UNDEF(&tmp_prop_value);
2889 			}
2890 			doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2891 
2892 			zend_type type = property_info->type;
2893 			/* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2894 			zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2895 			new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2896 
2897 			if (property_info->attributes) {
2898 				new_prop->attributes = property_info->attributes;
2899 
2900 				if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2901 					GC_ADDREF(new_prop->attributes);
2902 				}
2903 			}
2904 			if (property_info->hooks) {
2905 				zend_function **hooks = new_prop->hooks =
2906 					zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2907 				memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2908 				for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2909 					if (hooks[i]) {
2910 						zend_function *old_fn = hooks[i];
2911 
2912 						/* Hooks are not yet supported for internal properties. */
2913 						ZEND_ASSERT(ZEND_USER_CODE(old_fn->type));
2914 
2915 						/* Copy the function, because we need to adjust the scope. */
2916 						zend_function *new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2917 						memcpy(new_fn, old_fn, sizeof(zend_op_array));
2918 						new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
2919 						new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE;
2920 						new_fn->common.prop_info = new_prop;
2921 						function_add_ref(new_fn);
2922 
2923 						zend_fixup_trait_method(new_fn, ce);
2924 
2925 						hooks[i] = new_fn;
2926 					}
2927 				}
2928 				ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2929 			}
2930 		} ZEND_HASH_FOREACH_END();
2931 	}
2932 }
2933 /* }}} */
2934 
zend_do_bind_traits(zend_class_entry * ce,zend_class_entry ** traits)2935 static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2936 {
2937 	HashTable **exclude_tables;
2938 	zend_class_entry **aliases;
2939 
2940 	ZEND_ASSERT(ce->num_traits > 0);
2941 
2942 	/* complete initialization of trait structures in ce */
2943 	zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases);
2944 
2945 	/* first care about all methods to be flattened into the class */
2946 	zend_do_traits_method_binding(ce, traits, exclude_tables, aliases);
2947 
2948 	if (aliases) {
2949 		efree(aliases);
2950 	}
2951 
2952 	if (exclude_tables) {
2953 		efree(exclude_tables);
2954 	}
2955 
2956 	/* then flatten the constants and properties into it, to, mostly to notify developer about problems */
2957 	zend_do_traits_constant_binding(ce, traits);
2958 	zend_do_traits_property_binding(ce, traits);
2959 }
2960 /* }}} */
2961 
2962 #define MAX_ABSTRACT_INFO_CNT 3
2963 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
2964 #define DISPLAY_ABSTRACT_FN(idx) \
2965 	ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
2966 	ai.afn[idx] ? "::" : "", \
2967 	ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
2968 	ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
2969 
2970 typedef struct _zend_abstract_info {
2971 	const zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
2972 	int cnt;
2973 } zend_abstract_info;
2974 
zend_verify_abstract_class_function(const zend_function * fn,zend_abstract_info * ai)2975 static void zend_verify_abstract_class_function(const zend_function *fn, zend_abstract_info *ai) /* {{{ */
2976 {
2977 	if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
2978 		ai->afn[ai->cnt] = fn;
2979 	}
2980 	ai->cnt++;
2981 }
2982 /* }}} */
2983 
zend_verify_abstract_class(zend_class_entry * ce)2984 void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
2985 {
2986 	const zend_function *func;
2987 	zend_abstract_info ai;
2988 	bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
2989 	bool can_be_abstract = (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_ANON_CLASS)) == 0;
2990 	memset(&ai, 0, sizeof(ai));
2991 
2992 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
2993 		if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
2994 			/* If the class is explicitly abstract, we only check private abstract methods,
2995 			 * because only they must be declared in the same class. */
2996 			if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
2997 				zend_verify_abstract_class_function(func, &ai);
2998 			}
2999 		}
3000 	} ZEND_HASH_FOREACH_END();
3001 
3002 	if (!is_explicit_abstract) {
3003 		const zend_property_info *prop_info;
3004 		ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
3005 			if (prop_info->hooks) {
3006 				for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3007 					const zend_function *fn = prop_info->hooks[i];
3008 					if (fn && (fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3009 						zend_verify_abstract_class_function(fn, &ai);
3010 					}
3011 				}
3012 			}
3013 		} ZEND_HASH_FOREACH_END();
3014 	}
3015 
3016 	if (ai.cnt) {
3017 		if (!is_explicit_abstract && can_be_abstract) {
3018 			zend_error_noreturn(E_ERROR,
3019 				"%s %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3020 				zend_get_object_type_uc(ce),
3021 				ZSTR_VAL(ce->name), ai.cnt,
3022 				ai.cnt > 1 ? "s" : "",
3023 				ai.cnt > 1 ? "s" : "",
3024 				DISPLAY_ABSTRACT_FN(0),
3025 				DISPLAY_ABSTRACT_FN(1),
3026 				DISPLAY_ABSTRACT_FN(2)
3027 			);
3028 		} else {
3029 			zend_error_noreturn(E_ERROR,
3030 				"%s %s must implement %d abstract method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3031 				zend_get_object_type_uc(ce),
3032 				ZSTR_VAL(ce->name), ai.cnt,
3033 				ai.cnt > 1 ? "s" : "",
3034 				DISPLAY_ABSTRACT_FN(0),
3035 				DISPLAY_ABSTRACT_FN(1),
3036 				DISPLAY_ABSTRACT_FN(2)
3037 			);
3038 		}
3039 	} else {
3040 		/* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
3041 		ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3042 	}
3043 }
3044 /* }}} */
3045 
3046 typedef struct {
3047 	enum {
3048 		OBLIGATION_DEPENDENCY,
3049 		OBLIGATION_COMPATIBILITY,
3050 		OBLIGATION_PROPERTY_COMPATIBILITY,
3051 		OBLIGATION_CLASS_CONSTANT_COMPATIBILITY,
3052 		OBLIGATION_PROPERTY_HOOK,
3053 	} type;
3054 	union {
3055 		zend_class_entry *dependency_ce;
3056 		struct {
3057 			/* Traits may use temporary on-stack functions during inheritance checks,
3058 			 * so use copies of functions here as well. */
3059 			zend_function parent_fn;
3060 			zend_function child_fn;
3061 			zend_class_entry *child_scope;
3062 			zend_class_entry *parent_scope;
3063 		};
3064 		struct {
3065 			const zend_property_info *parent_prop;
3066 			const zend_property_info *child_prop;
3067 			prop_variance variance;
3068 		};
3069 		struct {
3070 			const zend_string *const_name;
3071 			const zend_class_constant *parent_const;
3072 			const zend_class_constant *child_const;
3073 		};
3074 		struct {
3075 			const zend_property_info *hooked_prop;
3076 			const zend_function *hook_func;
3077 		};
3078 	};
3079 } variance_obligation;
3080 
variance_obligation_dtor(zval * zv)3081 static void variance_obligation_dtor(zval *zv) {
3082 	efree(Z_PTR_P(zv));
3083 }
3084 
variance_obligation_ht_dtor(zval * zv)3085 static void variance_obligation_ht_dtor(zval *zv) {
3086 	zend_hash_destroy(Z_PTR_P(zv));
3087 	FREE_HASHTABLE(Z_PTR_P(zv));
3088 }
3089 
get_or_init_obligations_for_class(zend_class_entry * ce)3090 static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
3091 	HashTable *ht;
3092 	zend_ulong key;
3093 	if (!CG(delayed_variance_obligations)) {
3094 		ALLOC_HASHTABLE(CG(delayed_variance_obligations));
3095 		zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
3096 	}
3097 
3098 	key = (zend_ulong) (uintptr_t) ce;
3099 	ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
3100 	if (ht) {
3101 		return ht;
3102 	}
3103 
3104 	ALLOC_HASHTABLE(ht);
3105 	zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
3106 	zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
3107 	ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
3108 	return ht;
3109 }
3110 
add_dependency_obligation(zend_class_entry * ce,zend_class_entry * dependency_ce)3111 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
3112 	HashTable *obligations = get_or_init_obligations_for_class(ce);
3113 	variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3114 	obligation->type = OBLIGATION_DEPENDENCY;
3115 	obligation->dependency_ce = dependency_ce;
3116 	zend_hash_next_index_insert_ptr(obligations, obligation);
3117 }
3118 
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)3119 static void add_compatibility_obligation(
3120 		zend_class_entry *ce,
3121 		const zend_function *child_fn, zend_class_entry *child_scope,
3122 		const zend_function *parent_fn, zend_class_entry *parent_scope) {
3123 	HashTable *obligations = get_or_init_obligations_for_class(ce);
3124 	variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3125 	obligation->type = OBLIGATION_COMPATIBILITY;
3126 	/* Copy functions, because they may be stack-allocated in the case of traits. */
3127 	if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3128 		memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
3129 	} else {
3130 		memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
3131 	}
3132 	if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3133 		memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
3134 	} else {
3135 		memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
3136 	}
3137 	obligation->child_scope = child_scope;
3138 	obligation->parent_scope = parent_scope;
3139 	zend_hash_next_index_insert_ptr(obligations, obligation);
3140 }
3141 
add_property_compatibility_obligation(zend_class_entry * ce,const zend_property_info * child_prop,const zend_property_info * parent_prop,prop_variance variance)3142 static void add_property_compatibility_obligation(
3143 		zend_class_entry *ce, const zend_property_info *child_prop,
3144 		const zend_property_info *parent_prop, prop_variance variance) {
3145 	HashTable *obligations = get_or_init_obligations_for_class(ce);
3146 	variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3147 	obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
3148 	obligation->child_prop = child_prop;
3149 	obligation->parent_prop = parent_prop;
3150 	obligation->variance = variance;
3151 	zend_hash_next_index_insert_ptr(obligations, obligation);
3152 }
3153 
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)3154 static void add_class_constant_compatibility_obligation(
3155 		zend_class_entry *ce, const zend_class_constant *child_const,
3156 		const zend_class_constant *parent_const, const zend_string *const_name) {
3157 	HashTable *obligations = get_or_init_obligations_for_class(ce);
3158 	variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3159 	obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY;
3160 	obligation->const_name = const_name;
3161 	obligation->child_const = child_const;
3162 	obligation->parent_const = parent_const;
3163 	zend_hash_next_index_insert_ptr(obligations, obligation);
3164 }
3165 
add_property_hook_obligation(zend_class_entry * ce,const zend_property_info * hooked_prop,const zend_function * hook_func)3166 static void add_property_hook_obligation(
3167 		zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func) {
3168 	HashTable *obligations = get_or_init_obligations_for_class(ce);
3169 	variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3170 	obligation->type = OBLIGATION_PROPERTY_HOOK;
3171 	obligation->hooked_prop = hooked_prop;
3172 	obligation->hook_func = hook_func;
3173 	zend_hash_next_index_insert_ptr(obligations, obligation);
3174 }
3175 
3176 static void resolve_delayed_variance_obligations(zend_class_entry *ce);
3177 
check_variance_obligation(variance_obligation * obligation)3178 static void check_variance_obligation(variance_obligation *obligation) {
3179 	if (obligation->type == OBLIGATION_DEPENDENCY) {
3180 		zend_class_entry *dependency_ce = obligation->dependency_ce;
3181 		if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3182 			zend_class_entry *orig_linking_class = CG(current_linking_class);
3183 
3184 			CG(current_linking_class) =
3185 				(dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
3186 			resolve_delayed_variance_obligations(dependency_ce);
3187 			CG(current_linking_class) = orig_linking_class;
3188 		}
3189 	} else if (obligation->type == OBLIGATION_COMPATIBILITY) {
3190 		inheritance_status status = zend_do_perform_implementation_check(
3191 			&obligation->child_fn, obligation->child_scope,
3192 			&obligation->parent_fn, obligation->parent_scope);
3193 		if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3194 			emit_incompatible_method_error(
3195 				&obligation->child_fn, obligation->child_scope,
3196 				&obligation->parent_fn, obligation->parent_scope, status);
3197 		}
3198 		/* Either the compatibility check was successful or only threw a warning. */
3199 	} else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
3200 		verify_property_type_compatibility(obligation->parent_prop, obligation->child_prop, obligation->variance, true, true);
3201 	} else if (obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY) {
3202 		inheritance_status status =
3203 		class_constant_types_compatible(obligation->parent_const, obligation->child_const);
3204 		if (status != INHERITANCE_SUCCESS) {
3205 			emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name);
3206 		}
3207 	} else if (obligation->type == OBLIGATION_PROPERTY_HOOK) {
3208 		inheritance_status status = zend_verify_property_hook_variance(obligation->hooked_prop, obligation->hook_func);
3209 		if (status != INHERITANCE_SUCCESS) {
3210 			zend_hooked_property_variance_error(obligation->hooked_prop);
3211 		}
3212 	} else {
3213 		ZEND_UNREACHABLE();
3214 	}
3215 }
3216 
load_delayed_classes(zend_class_entry * ce)3217 static void load_delayed_classes(zend_class_entry *ce) {
3218 	HashTable *delayed_autoloads = CG(delayed_autoloads);
3219 	if (!delayed_autoloads) {
3220 		return;
3221 	}
3222 
3223 	/* Autoloading can trigger linking of another class, which may register new delayed autoloads.
3224 	 * For that reason, this code uses a loop that pops and loads the first element of the HT. If
3225 	 * this triggers linking, then the remaining classes may get loaded when linking the newly
3226 	 * loaded class. This is important, as otherwise necessary dependencies may not be available
3227 	 * if the new class is lower in the hierarchy than the current one. */
3228 	HashPosition pos = 0;
3229 	zend_string *name;
3230 	zend_ulong idx;
3231 	while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
3232 			!= HASH_KEY_NON_EXISTENT) {
3233 		zend_string_addref(name);
3234 		zend_hash_del(delayed_autoloads, name);
3235 		zend_lookup_class(name);
3236 		zend_string_release(name);
3237 		if (EG(exception)) {
3238 			zend_exception_uncaught_error(
3239 				"During inheritance of %s, while autoloading %s",
3240 				ZSTR_VAL(ce->name), ZSTR_VAL(name));
3241 		}
3242 	}
3243 }
3244 
resolve_delayed_variance_obligations(zend_class_entry * ce)3245 static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
3246 	HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
3247 	zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
3248 
3249 	ZEND_ASSERT(all_obligations != NULL);
3250 	obligations = zend_hash_index_find_ptr(all_obligations, num_key);
3251 	ZEND_ASSERT(obligations != NULL);
3252 
3253 	variance_obligation *obligation;
3254 	ZEND_HASH_FOREACH_PTR(obligations, obligation) {
3255 		check_variance_obligation(obligation);
3256 	} ZEND_HASH_FOREACH_END();
3257 
3258 	zend_inheritance_check_override(ce);
3259 
3260 	ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
3261 	ce->ce_flags |= ZEND_ACC_LINKED;
3262 	zend_hash_index_del(all_obligations, num_key);
3263 }
3264 
check_unrecoverable_load_failure(const zend_class_entry * ce)3265 static void check_unrecoverable_load_failure(const zend_class_entry *ce) {
3266 	/* If this class has been used while unlinked through a variance obligation, it is not legal
3267 	 * to remove the class from the class table and throw an exception, because there is already
3268 	 * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
3269 	 * a fatal error, as would happen if we did not allow exceptions in the first place. */
3270 	if (CG(unlinked_uses)
3271 			&& zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t)ce) == SUCCESS) {
3272 		zend_exception_uncaught_error(
3273 			"During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
3274 	}
3275 }
3276 
3277 #define zend_update_inherited_handler(handler) do { \
3278 		if (ce->handler == (zend_function*)op_array) { \
3279 			ce->handler = (zend_function*)new_op_array; \
3280 		} \
3281 	} while (0)
3282 
zend_lazy_method_load(zend_op_array * op_array,zend_class_entry * ce,const zend_class_entry * pce)3283 static zend_op_array *zend_lazy_method_load(
3284 		zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3285 	ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3286 	ZEND_ASSERT(op_array->scope == pce);
3287 	ZEND_ASSERT(op_array->prototype == NULL);
3288 	zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3289 	memcpy(new_op_array, op_array, sizeof(zend_op_array));
3290 	new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3291 	new_op_array->scope = ce;
3292 	ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3293 	ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3294 
3295 	return new_op_array;
3296 }
3297 
zend_lazy_class_load(zend_class_entry * pce)3298 static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
3299 {
3300 	zend_class_entry *ce;
3301 	Bucket *p, *end;
3302 
3303 	ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3304 	memcpy(ce, pce, sizeof(zend_class_entry));
3305 	ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
3306 	ce->refcount = 1;
3307 	ce->inheritance_cache = NULL;
3308 	if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3309 		ZEND_MAP_PTR_NEW(ce->mutable_data);
3310 	} else {
3311 		ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3312 	}
3313 
3314 	/* properties */
3315 	if (ce->default_properties_table) {
3316 		zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3317 		zval *src = ce->default_properties_table;
3318 		zval *end = src + ce->default_properties_count;
3319 
3320 		ce->default_properties_table = dst;
3321 		for (; src != end; src++, dst++) {
3322 			ZVAL_COPY_VALUE_PROP(dst, src);
3323 		}
3324 	}
3325 
3326 	/* methods */
3327 	ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
3328 	if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
3329 		p = emalloc(HT_SIZE(&ce->function_table));
3330 		memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
3331 		HT_SET_DATA_ADDR(&ce->function_table, p);
3332 		p = ce->function_table.arData;
3333 		end = p + ce->function_table.nNumUsed;
3334 		for (; p != end; p++) {
3335 			zend_op_array *op_array = Z_PTR(p->val);
3336 			zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3337 
3338 			zend_update_inherited_handler(constructor);
3339 			zend_update_inherited_handler(destructor);
3340 			zend_update_inherited_handler(clone);
3341 			zend_update_inherited_handler(__get);
3342 			zend_update_inherited_handler(__set);
3343 			zend_update_inherited_handler(__call);
3344 			zend_update_inherited_handler(__isset);
3345 			zend_update_inherited_handler(__unset);
3346 			zend_update_inherited_handler(__tostring);
3347 			zend_update_inherited_handler(__callstatic);
3348 			zend_update_inherited_handler(__debugInfo);
3349 			zend_update_inherited_handler(__serialize);
3350 			zend_update_inherited_handler(__unserialize);
3351 		}
3352 	}
3353 
3354 	/* static members */
3355 	if (ce->default_static_members_table) {
3356 		zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
3357 		zval *src = ce->default_static_members_table;
3358 		zval *end = src + ce->default_static_members_count;
3359 
3360 		ce->default_static_members_table = dst;
3361 		for (; src != end; src++, dst++) {
3362 			ZVAL_COPY_VALUE(dst, src);
3363 		}
3364 	}
3365 	ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3366 
3367 	/* properties_info */
3368 	if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
3369 		p = emalloc(HT_SIZE(&ce->properties_info));
3370 		memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
3371 		HT_SET_DATA_ADDR(&ce->properties_info, p);
3372 		p = ce->properties_info.arData;
3373 		end = p + ce->properties_info.nNumUsed;
3374 		for (; p != end; p++) {
3375 			zend_property_info *prop_info, *new_prop_info;
3376 
3377 			prop_info = Z_PTR(p->val);
3378 			ZEND_ASSERT(prop_info->ce == pce);
3379 			ZEND_ASSERT(prop_info->prototype == prop_info);
3380 			new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3381 			Z_PTR(p->val) = new_prop_info;
3382 			memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3383 			new_prop_info->ce = ce;
3384 			new_prop_info->prototype = new_prop_info;
3385 			/* Deep copy the type information */
3386 			zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3387 			if (new_prop_info->hooks) {
3388 				new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3389 				memcpy(new_prop_info->hooks, prop_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3390 				for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3391 					if (new_prop_info->hooks[i]) {
3392 						zend_op_array *hook = zend_lazy_method_load((zend_op_array *) new_prop_info->hooks[i], ce, pce);
3393 						ZEND_ASSERT(hook->prop_info == prop_info);
3394 						hook->prop_info = new_prop_info;
3395 						new_prop_info->ce = ce;
3396 						new_prop_info->hooks[i] = (zend_function *) hook;
3397 					}
3398 				}
3399 			}
3400 		}
3401 	}
3402 
3403 	/* constants table */
3404 	if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
3405 		p = emalloc(HT_SIZE(&ce->constants_table));
3406 		memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
3407 		HT_SET_DATA_ADDR(&ce->constants_table, p);
3408 		p = ce->constants_table.arData;
3409 		end = p + ce->constants_table.nNumUsed;
3410 		for (; p != end; p++) {
3411 			zend_class_constant *c, *new_c;
3412 
3413 			c = Z_PTR(p->val);
3414 			ZEND_ASSERT(c->ce == pce);
3415 			new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3416 			Z_PTR(p->val) = new_c;
3417 			memcpy(new_c, c, sizeof(zend_class_constant));
3418 			new_c->ce = ce;
3419 		}
3420 	}
3421 
3422 	return ce;
3423 }
3424 
3425 #ifndef ZEND_WIN32
3426 # define UPDATE_IS_CACHEABLE(ce) do { \
3427 			if ((ce)->type == ZEND_USER_CLASS) { \
3428 				is_cacheable &= (ce)->ce_flags; \
3429 			} \
3430 		} while (0)
3431 #else
3432 // TODO: ASLR may cause different addresses in different workers ???
3433 # define UPDATE_IS_CACHEABLE(ce) do { \
3434 			is_cacheable &= (ce)->ce_flags; \
3435 		} while (0)
3436 #endif
3437 
zend_do_link_class(zend_class_entry * ce,zend_string * lc_parent_name,zend_string * key)3438 ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key) /* {{{ */
3439 {
3440 	/* Load parent/interface dependencies first, so we can still gracefully abort linking
3441 	 * with an exception and remove the class from the class table. This is only possible
3442 	 * if no variance obligations on the current class have been added during autoloading. */
3443 	zend_class_entry *parent = NULL;
3444 	zend_class_entry **traits_and_interfaces = NULL;
3445 	zend_class_entry *proto = NULL;
3446 	zend_class_entry *orig_linking_class;
3447 	uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3448 	uint32_t i, j;
3449 	zval *zv;
3450 	ALLOCA_FLAG(use_heap)
3451 
3452 	SET_ALLOCA_FLAG(use_heap);
3453 	ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
3454 
3455 	if (ce->parent_name) {
3456 		parent = zend_fetch_class_by_name(
3457 			ce->parent_name, lc_parent_name,
3458 			ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3459 		if (!parent) {
3460 			check_unrecoverable_load_failure(ce);
3461 			return NULL;
3462 		}
3463 		UPDATE_IS_CACHEABLE(parent);
3464 	}
3465 
3466 	if (ce->num_traits || ce->num_interfaces) {
3467 		traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3468 
3469 		for (i = 0; i < ce->num_traits; i++) {
3470 			zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
3471 				ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
3472 			if (UNEXPECTED(trait == NULL)) {
3473 				free_alloca(traits_and_interfaces, use_heap);
3474 				return NULL;
3475 			}
3476 			if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
3477 				zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
3478 				free_alloca(traits_and_interfaces, use_heap);
3479 				return NULL;
3480 			}
3481 			for (j = 0; j < i; j++) {
3482 				if (traits_and_interfaces[j] == trait) {
3483 					/* skip duplications */
3484 					trait = NULL;
3485 					break;
3486 				}
3487 			}
3488 			traits_and_interfaces[i] = trait;
3489 			if (trait) {
3490 				UPDATE_IS_CACHEABLE(trait);
3491 			}
3492 		}
3493 	}
3494 
3495 	if (ce->num_interfaces) {
3496 		for (i = 0; i < ce->num_interfaces; i++) {
3497 			zend_class_entry *iface = zend_fetch_class_by_name(
3498 				ce->interface_names[i].name, ce->interface_names[i].lc_name,
3499 				ZEND_FETCH_CLASS_INTERFACE |
3500 				ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3501 			if (!iface) {
3502 				check_unrecoverable_load_failure(ce);
3503 				free_alloca(traits_and_interfaces, use_heap);
3504 				return NULL;
3505 			}
3506 			traits_and_interfaces[ce->num_traits + i] = iface;
3507 			if (iface) {
3508 				UPDATE_IS_CACHEABLE(iface);
3509 			}
3510 		}
3511 	}
3512 
3513 #ifndef ZEND_WIN32
3514 	if (ce->ce_flags & ZEND_ACC_ENUM) {
3515 		/* We will add internal methods. */
3516 		is_cacheable = false;
3517 	}
3518 #endif
3519 
3520 	bool orig_record_errors = EG(record_errors);
3521 
3522 	if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3523 		if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3524 			zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3525 			if (ret) {
3526 				if (traits_and_interfaces) {
3527 					free_alloca(traits_and_interfaces, use_heap);
3528 				}
3529 				zv = zend_hash_find_known_hash(CG(class_table), key);
3530 				Z_CE_P(zv) = ret;
3531 				return ret;
3532 			}
3533 
3534 			/* Make sure warnings (such as deprecations) thrown during inheritance
3535 			 * will be recorded in the inheritance cache. */
3536 			zend_begin_record_errors();
3537 		} else {
3538 			is_cacheable = 0;
3539 		}
3540 		proto = ce;
3541 	}
3542 
3543 	zend_try {
3544 		if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3545 			/* Lazy class loading */
3546 			ce = zend_lazy_class_load(ce);
3547 			zv = zend_hash_find_known_hash(CG(class_table), key);
3548 			Z_CE_P(zv) = ce;
3549 		} else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3550 			/* Lazy class loading */
3551 			ce = zend_lazy_class_load(ce);
3552 			ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3553 			zv = zend_hash_find_known_hash(CG(class_table), key);
3554 			Z_CE_P(zv) = ce;
3555 		}
3556 
3557 		if (CG(unlinked_uses)) {
3558 			zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3559 		}
3560 
3561 		orig_linking_class = CG(current_linking_class);
3562 		CG(current_linking_class) = is_cacheable ? ce : NULL;
3563 
3564 		if (ce->ce_flags & ZEND_ACC_ENUM) {
3565 			/* Only register builtin enum methods during inheritance to avoid persisting them in
3566 			 * opcache. */
3567 			zend_enum_register_funcs(ce);
3568 		}
3569 
3570 		if (parent) {
3571 			if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3572 				add_dependency_obligation(ce, parent);
3573 			}
3574 			zend_do_inheritance(ce, parent);
3575 		}
3576 		if (ce->num_traits) {
3577 			zend_do_bind_traits(ce, traits_and_interfaces);
3578 		}
3579 		if (ce->num_interfaces) {
3580 			/* Also copy the parent interfaces here, so we don't need to reallocate later. */
3581 			uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3582 			zend_class_entry **interfaces = emalloc(
3583 					sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3584 
3585 			if (num_parent_interfaces) {
3586 				memcpy(interfaces, parent->interfaces,
3587 					   sizeof(zend_class_entry *) * num_parent_interfaces);
3588 			}
3589 			memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3590 				   sizeof(zend_class_entry *) * ce->num_interfaces);
3591 
3592 			zend_do_implement_interfaces(ce, interfaces);
3593 		} else if (parent && parent->num_interfaces) {
3594 			zend_do_inherit_interfaces(ce, parent);
3595 		}
3596 		if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
3597 			&& (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
3598 				) {
3599 			zend_verify_abstract_class(ce);
3600 		}
3601 		if (ce->ce_flags & ZEND_ACC_ENUM) {
3602 			zend_verify_enum(ce);
3603 		}
3604 		if (ce->num_hooked_prop_variance_checks) {
3605 			const zend_property_info *prop_info;
3606 			ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
3607 				if (prop_info->ce == ce && prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
3608 					switch (zend_verify_property_hook_variance(prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
3609 						case INHERITANCE_SUCCESS:
3610 							break;
3611 						case INHERITANCE_ERROR:
3612 							zend_hooked_property_variance_error(prop_info);
3613 							break;
3614 						case INHERITANCE_UNRESOLVED:
3615 							add_property_hook_obligation(ce, prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET]);
3616 							break;
3617 						case INHERITANCE_WARNING:
3618 							ZEND_UNREACHABLE();
3619 					}
3620 				}
3621 			} ZEND_HASH_FOREACH_END();
3622 		}
3623 
3624 		/* Normally Stringable is added during compilation. However, if it is imported from a trait,
3625 		 * we need to explicitly add the interface here. */
3626 		if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3627 			&& !zend_class_implements_interface(ce, zend_ce_stringable)) {
3628 			ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
3629 			ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
3630 			ce->num_interfaces++;
3631 			ce->interfaces = perealloc(ce->interfaces,
3632 									   sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
3633 			ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
3634 			do_interface_implementation(ce, zend_ce_stringable);
3635 		}
3636 
3637 		zend_build_properties_info_table(ce);
3638 	} zend_catch {
3639 		/* Do not leak recorded errors to the next linked class. */
3640 		if (!orig_record_errors) {
3641 			EG(record_errors) = false;
3642 			zend_free_recorded_errors();
3643 		}
3644 		zend_bailout();
3645 	} zend_end_try();
3646 
3647 	EG(record_errors) = orig_record_errors;
3648 
3649 	if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
3650 		zend_inheritance_check_override(ce);
3651 		ce->ce_flags |= ZEND_ACC_LINKED;
3652 	} else {
3653 		ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
3654 		if (CG(current_linking_class)) {
3655 			ce->ce_flags |= ZEND_ACC_CACHEABLE;
3656 		}
3657 		load_delayed_classes(ce);
3658 		if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3659 			resolve_delayed_variance_obligations(ce);
3660 		}
3661 		if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3662 			ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
3663 		} else {
3664 			CG(current_linking_class) = NULL;
3665 		}
3666 	}
3667 
3668 	if (!CG(current_linking_class)) {
3669 		is_cacheable = 0;
3670 	}
3671 	CG(current_linking_class) = orig_linking_class;
3672 
3673 	if (is_cacheable) {
3674 		HashTable *ht = (HashTable*)ce->inheritance_cache;
3675 		zend_class_entry *new_ce;
3676 
3677 		ce->inheritance_cache = NULL;
3678 		new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3679 		if (new_ce) {
3680 			zv = zend_hash_find_known_hash(CG(class_table), key);
3681 			ce = new_ce;
3682 			Z_CE_P(zv) = ce;
3683 		}
3684 		if (ht) {
3685 			zend_hash_destroy(ht);
3686 			FREE_HASHTABLE(ht);
3687 		}
3688 	}
3689 
3690 	if (!orig_record_errors) {
3691 		zend_free_recorded_errors();
3692 	}
3693 	if (traits_and_interfaces) {
3694 		free_alloca(traits_and_interfaces, use_heap);
3695 	}
3696 
3697 	if (ZSTR_HAS_CE_CACHE(ce->name)) {
3698 		ZSTR_SET_CE_CACHE(ce->name, ce);
3699 	}
3700 
3701 	return ce;
3702 }
3703 /* }}} */
3704 
3705 /* 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)3706 static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
3707 {
3708 	zend_string *key;
3709 	zend_function *parent_func;
3710 	const zend_property_info *parent_info;
3711 	const zend_class_constant *parent_const;
3712 	inheritance_status overall_status = INHERITANCE_SUCCESS;
3713 
3714 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3715 		zval *zv = zend_hash_find_known_hash(&ce->function_table, key);
3716 		if (zv) {
3717 			zend_function *child_func = Z_FUNC_P(zv);
3718 			inheritance_status status =
3719 				do_inheritance_check_on_method(
3720 					child_func, child_func->common.scope,
3721 					parent_func, parent_func->common.scope,
3722 					ce, NULL,
3723 					ZEND_INHERITANCE_CHECK_SILENT | ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
3724 			if (UNEXPECTED(status == INHERITANCE_WARNING)) {
3725 				overall_status = INHERITANCE_WARNING;
3726 			} else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3727 				return status;
3728 			}
3729 		}
3730 	} ZEND_HASH_FOREACH_END();
3731 
3732 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3733 		const zval *zv;
3734 		if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3735 			continue;
3736 		}
3737 
3738 		zv = zend_hash_find_known_hash(&ce->properties_info, key);
3739 		if (zv) {
3740 			const zend_property_info *child_info = Z_PTR_P(zv);
3741 			if (ZEND_TYPE_IS_SET(child_info->type)) {
3742 				inheritance_status status = verify_property_type_compatibility(parent_info, child_info, prop_get_variance(parent_info), false, false);
3743 				if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3744 					return status;
3745 				}
3746 			}
3747 		}
3748 	} ZEND_HASH_FOREACH_END();
3749 
3750 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3751 		const zval *zv;
3752 		if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3753 			continue;
3754 		}
3755 
3756 		zv = zend_hash_find_known_hash(&ce->constants_table, key);
3757 		if (zv) {
3758 			const zend_class_constant *child_const = Z_PTR_P(zv);
3759 			if (ZEND_TYPE_IS_SET(child_const->type)) {
3760 				inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3761 				ZEND_ASSERT(status != INHERITANCE_WARNING);
3762 				if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3763 					return status;
3764 				}
3765 			}
3766 		}
3767 	} ZEND_HASH_FOREACH_END();
3768 
3769 	return overall_status;
3770 }
3771 /* }}} */
3772 
register_early_bound_ce(zval * delayed_early_binding,zend_string * lcname,zend_class_entry * ce)3773 static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3774 	if (delayed_early_binding) {
3775 		if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3776 			if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3777 				Z_CE_P(delayed_early_binding) = ce;
3778 				return true;
3779 			}
3780 		} else {
3781 			/* If preloading is used, don't replace the existing bucket, add a new one. */
3782 			if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3783 				return true;
3784 			}
3785 		}
3786 		zend_class_entry *old_ce = zend_hash_find_ptr(EG(class_table), lcname);
3787 		ZEND_ASSERT(old_ce);
3788 		zend_class_redeclaration_error(E_COMPILE_ERROR, old_ce);
3789 		return false;
3790 	}
3791 	if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3792 		return true;
3793 	}
3794 	return false;
3795 }
3796 
zend_try_early_bind(zend_class_entry * ce,zend_class_entry * parent_ce,zend_string * lcname,zval * delayed_early_binding)3797 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) /* {{{ */
3798 {
3799 	inheritance_status status;
3800 	zend_class_entry *proto = NULL;
3801 	zend_class_entry *orig_linking_class;
3802 
3803 	if (ce->ce_flags & ZEND_ACC_LINKED) {
3804 		ZEND_ASSERT(ce->parent == NULL);
3805 		if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3806 			return NULL;
3807 		}
3808 		zend_observer_class_linked_notify(ce, lcname);
3809 		return ce;
3810 	}
3811 
3812 	uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3813 	UPDATE_IS_CACHEABLE(parent_ce);
3814 	if (is_cacheable) {
3815 		if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
3816 			zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
3817 			if (ret) {
3818 				if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
3819 					return NULL;
3820 				}
3821 				zend_observer_class_linked_notify(ret, lcname);
3822 				return ret;
3823 			}
3824 		} else {
3825 			is_cacheable = 0;
3826 		}
3827 		proto = ce;
3828 	}
3829 
3830 	orig_linking_class = CG(current_linking_class);
3831 	CG(current_linking_class) = NULL;
3832 	status = zend_can_early_bind(ce, parent_ce);
3833 	CG(current_linking_class) = orig_linking_class;
3834 	if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
3835 		if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3836 			/* Lazy class loading */
3837 			ce = zend_lazy_class_load(ce);
3838 		} else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3839 			/* Lazy class loading */
3840 			ce = zend_lazy_class_load(ce);
3841 			ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
3842 		}
3843 
3844 		if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3845 			return NULL;
3846 		}
3847 
3848 		orig_linking_class = CG(current_linking_class);
3849 		CG(current_linking_class) = is_cacheable ? ce : NULL;
3850 
3851 		zend_try{
3852 			CG(zend_lineno) = ce->info.user.line_start;
3853 
3854 			if (is_cacheable) {
3855 				zend_begin_record_errors();
3856 			}
3857 
3858 			zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
3859 			if (parent_ce && parent_ce->num_interfaces) {
3860 				zend_do_inherit_interfaces(ce, parent_ce);
3861 			}
3862 			zend_build_properties_info_table(ce);
3863 			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) {
3864 				zend_verify_abstract_class(ce);
3865 			}
3866 			zend_inheritance_check_override(ce);
3867 			ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
3868 			ce->ce_flags |= ZEND_ACC_LINKED;
3869 
3870 			CG(current_linking_class) = orig_linking_class;
3871 		} zend_catch {
3872 			EG(record_errors) = false;
3873 			zend_free_recorded_errors();
3874 			zend_bailout();
3875 		} zend_end_try();
3876 
3877 		EG(record_errors) = false;
3878 
3879 		if (is_cacheable) {
3880 			HashTable *ht = (HashTable*)ce->inheritance_cache;
3881 			zend_class_entry *new_ce;
3882 
3883 			ce->inheritance_cache = NULL;
3884 			new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3885 			if (new_ce) {
3886 				zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3887 				ce = new_ce;
3888 				Z_CE_P(zv) = ce;
3889 			}
3890 			if (ht) {
3891 				zend_hash_destroy(ht);
3892 				FREE_HASHTABLE(ht);
3893 			}
3894 		}
3895 
3896 		if (ZSTR_HAS_CE_CACHE(ce->name)) {
3897 			ZSTR_SET_CE_CACHE(ce->name, ce);
3898 		}
3899 		zend_observer_class_linked_notify(ce, lcname);
3900 
3901 		return ce;
3902 	}
3903 	return NULL;
3904 }
3905 /* }}} */
3906