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