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