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