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