xref: /PHP-7.2/Zend/zend_inheritance.c (revision d19b6aa5)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2018 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@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
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_smart_str.h"
26 #include "zend_operators.h"
27 
overriden_ptr_dtor(zval * zv)28 static void overriden_ptr_dtor(zval *zv) /* {{{ */
29 {
30 	efree_size(Z_PTR_P(zv), sizeof(zend_function));
31 }
32 /* }}} */
33 
zend_duplicate_property_info(zend_property_info * property_info)34 static zend_property_info *zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
35 {
36 	zend_property_info* new_property_info;
37 
38 	new_property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
39 	memcpy(new_property_info, property_info, sizeof(zend_property_info));
40 	zend_string_addref(new_property_info->name);
41 	if (new_property_info->doc_comment) {
42 		zend_string_addref(new_property_info->doc_comment);
43 	}
44 	return new_property_info;
45 }
46 /* }}} */
47 
zend_duplicate_property_info_internal(zend_property_info * property_info)48 static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
49 {
50 	zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1);
51 	memcpy(new_property_info, property_info, sizeof(zend_property_info));
52 	zend_string_addref(new_property_info->name);
53 	return new_property_info;
54 }
55 /* }}} */
56 
zend_duplicate_function(zend_function * func,zend_class_entry * ce)57 static zend_function *zend_duplicate_function(zend_function *func, zend_class_entry *ce) /* {{{ */
58 {
59 	zend_function *new_function;
60 
61 	if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
62 		if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
63 			new_function = pemalloc(sizeof(zend_internal_function), 1);
64 			memcpy(new_function, func, sizeof(zend_internal_function));
65 		} else {
66 			new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
67 			memcpy(new_function, func, sizeof(zend_internal_function));
68 			new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
69 		}
70 		if (EXPECTED(new_function->common.function_name)) {
71 			zend_string_addref(new_function->common.function_name);
72 		}
73 	} else {
74 		if (func->op_array.refcount) {
75 			(*func->op_array.refcount)++;
76 		}
77 		if (EXPECTED(!func->op_array.static_variables)) {
78 			/* reuse the same op_array structure */
79 			return func;
80 		}
81 		if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
82 			GC_REFCOUNT(func->op_array.static_variables)++;
83 		}
84 		new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
85 		memcpy(new_function, func, sizeof(zend_op_array));
86 	}
87 	return new_function;
88 }
89 /* }}} */
90 
do_inherit_parent_constructor(zend_class_entry * ce)91 static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
92 {
93 	ZEND_ASSERT(ce->parent != NULL);
94 
95 	/* You cannot change create_object */
96 	ce->create_object = ce->parent->create_object;
97 
98 	/* Inherit special functions if needed */
99 	if (EXPECTED(!ce->get_iterator)) {
100 		ce->get_iterator = ce->parent->get_iterator;
101 	}
102 	if (EXPECTED(!ce->iterator_funcs.funcs)) {
103 		ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
104 	}
105 	if (EXPECTED(!ce->__get)) {
106 		ce->__get = ce->parent->__get;
107 	}
108 	if (EXPECTED(!ce->__set)) {
109 		ce->__set = ce->parent->__set;
110 	}
111 	if (EXPECTED(!ce->__unset)) {
112 		ce->__unset = ce->parent->__unset;
113 	}
114 	if (EXPECTED(!ce->__isset)) {
115 		ce->__isset = ce->parent->__isset;
116 	}
117 	if (EXPECTED(!ce->__call)) {
118 		ce->__call = ce->parent->__call;
119 	}
120 	if (EXPECTED(!ce->__callstatic)) {
121 		ce->__callstatic = ce->parent->__callstatic;
122 	}
123 	if (EXPECTED(!ce->__tostring)) {
124 		ce->__tostring = ce->parent->__tostring;
125 	}
126 	if (EXPECTED(!ce->clone)) {
127 		ce->clone = ce->parent->clone;
128 	}
129 	if (EXPECTED(!ce->serialize)) {
130 		ce->serialize = ce->parent->serialize;
131 	}
132 	if (EXPECTED(!ce->unserialize)) {
133 		ce->unserialize = ce->parent->unserialize;
134 	}
135 	if (!ce->destructor) {
136 		ce->destructor = ce->parent->destructor;
137 	}
138 	if (EXPECTED(!ce->__debugInfo)) {
139 		ce->__debugInfo = ce->parent->__debugInfo;
140 	}
141 
142 	if (ce->constructor) {
143 		if (ce->parent->constructor && UNEXPECTED(ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) {
144 			zend_error_noreturn(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
145 				ZSTR_VAL(ce->parent->name), ZSTR_VAL(ce->parent->constructor->common.function_name),
146 				ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
147 		}
148 		return;
149 	}
150 
151 	ce->constructor = ce->parent->constructor;
152 }
153 /* }}} */
154 
zend_visibility_string(uint32_t fn_flags)155 char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
156 {
157 	if (fn_flags & ZEND_ACC_PRIVATE) {
158 		return "private";
159 	}
160 	if (fn_flags & ZEND_ACC_PROTECTED) {
161 		return "protected";
162 	}
163 	if (fn_flags & ZEND_ACC_PUBLIC) {
164 		return "public";
165 	}
166 	return "";
167 }
168 /* }}} */
169 
zend_iterable_compatibility_check(zend_arg_info * arg_info)170 static zend_always_inline zend_bool zend_iterable_compatibility_check(zend_arg_info *arg_info) /* {{{ */
171 {
172 	if (ZEND_TYPE_CODE(arg_info->type) == IS_ARRAY) {
173 		return 1;
174 	}
175 
176 	if (ZEND_TYPE_IS_CLASS(arg_info->type) && zend_string_equals_literal_ci(ZEND_TYPE_NAME(arg_info->type), "Traversable")) {
177 		return 1;
178 	}
179 
180 	return 0;
181 }
182 /* }}} */
183 
zend_do_perform_type_hint_check(const zend_function * fe,zend_arg_info * fe_arg_info,const zend_function * proto,zend_arg_info * proto_arg_info)184 static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_info *fe_arg_info, const zend_function *proto, zend_arg_info *proto_arg_info) /* {{{ */
185 {
186 	ZEND_ASSERT(ZEND_TYPE_IS_SET(fe_arg_info->type) && ZEND_TYPE_IS_SET(proto_arg_info->type));
187 
188 	if (ZEND_TYPE_IS_CLASS(fe_arg_info->type) && ZEND_TYPE_IS_CLASS(proto_arg_info->type)) {
189 		zend_string *fe_class_name, *proto_class_name;
190 		const char *class_name;
191 		size_t class_name_len;
192 
193 		fe_class_name = ZEND_TYPE_NAME(fe_arg_info->type);
194 		class_name = ZSTR_VAL(fe_class_name);
195 		class_name_len = ZSTR_LEN(fe_class_name);
196 		if (class_name_len == sizeof("parent")-1 && !strcasecmp(class_name, "parent") && fe->common.scope && fe->common.scope->parent) {
197 			fe_class_name = zend_string_copy(fe->common.scope->parent->name);
198 		} else if (class_name_len == sizeof("self")-1 && !strcasecmp(class_name, "self") && fe->common.scope) {
199 			fe_class_name = zend_string_copy(fe->common.scope->name);
200 		} else {
201 			zend_string_addref(fe_class_name);
202 		}
203 
204 		proto_class_name = ZEND_TYPE_NAME(proto_arg_info->type);
205 		class_name = ZSTR_VAL(proto_class_name);
206 		class_name_len = ZSTR_LEN(proto_class_name);
207 		if (class_name_len == sizeof("parent")-1 && !strcasecmp(class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
208 			proto_class_name = zend_string_copy(proto->common.scope->parent->name);
209 		} else if (class_name_len == sizeof("self")-1 && !strcasecmp(class_name, "self") && proto->common.scope) {
210 			proto_class_name = zend_string_copy(proto->common.scope->name);
211 		} else {
212 			zend_string_addref(proto_class_name);
213 		}
214 
215 		if (fe_class_name != proto_class_name && strcasecmp(ZSTR_VAL(fe_class_name), ZSTR_VAL(proto_class_name)) != 0) {
216 			if (fe->common.type != ZEND_USER_FUNCTION) {
217 				zend_string_release(proto_class_name);
218 				zend_string_release(fe_class_name);
219 				return 0;
220 			} else {
221 				zend_class_entry *fe_ce, *proto_ce;
222 
223 				fe_ce = zend_lookup_class(fe_class_name);
224 				proto_ce = zend_lookup_class(proto_class_name);
225 
226 				/* Check for class alias */
227 				if (!fe_ce || !proto_ce ||
228 						fe_ce->type == ZEND_INTERNAL_CLASS ||
229 						proto_ce->type == ZEND_INTERNAL_CLASS ||
230 						fe_ce != proto_ce) {
231 					zend_string_release(proto_class_name);
232 					zend_string_release(fe_class_name);
233 					return 0;
234 				}
235 			}
236 		}
237 		zend_string_release(proto_class_name);
238 		zend_string_release(fe_class_name);
239 	} else if (ZEND_TYPE_CODE(fe_arg_info->type) != ZEND_TYPE_CODE(proto_arg_info->type)) {
240 		/* Incompatible built-in types */
241 		return 0;
242 	}
243 
244 	return 1;
245 }
246 /* }}} */
247 
zend_do_perform_arg_type_hint_check(const zend_function * fe,zend_arg_info * fe_arg_info,const zend_function * proto,zend_arg_info * proto_arg_info)248 static int zend_do_perform_arg_type_hint_check(const zend_function *fe, zend_arg_info *fe_arg_info, const zend_function *proto, zend_arg_info *proto_arg_info) /* {{{ */
249 {
250 	if (!ZEND_TYPE_IS_SET(fe_arg_info->type)) {
251 		/* Child with no type is always compatible */
252 		return 1;
253 	}
254 
255 	if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
256 		/* Child defines a type, but parent doesn't, violates LSP */
257 		return 0;
258 	}
259 
260 	return zend_do_perform_type_hint_check(fe, fe_arg_info, proto, proto_arg_info);
261 }
262 /* }}} */
263 
zend_do_perform_implementation_check(const zend_function * fe,const zend_function * proto)264 static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto) /* {{{ */
265 {
266 	uint32_t i, num_args;
267 
268 	/* If it's a user function then arg_info == NULL means we don't have any parameters but
269 	 * we still need to do the arg number checks.  We are only willing to ignore this for internal
270 	 * functions because extensions don't always define arg_info.
271 	 */
272 	if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
273 		return 1;
274 	}
275 
276 	/* Checks for constructors only if they are declared in an interface,
277 	 * or explicitly marked as abstract
278 	 */
279 	if ((fe->common.fn_flags & ZEND_ACC_CTOR)
280 		&& ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
281 			&& (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
282 		return 1;
283 	}
284 
285 	/* If the prototype method is private do not enforce a signature */
286 	if (proto->common.fn_flags & ZEND_ACC_PRIVATE) {
287 		return 1;
288 	}
289 
290 	/* check number of arguments */
291 	if (proto->common.required_num_args < fe->common.required_num_args
292 		|| proto->common.num_args > fe->common.num_args) {
293 		return 0;
294 	}
295 
296 	/* by-ref constraints on return values are covariant */
297 	if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
298 		&& !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
299 		return 0;
300 	}
301 
302 	if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
303 		&& !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
304 		return 0;
305 	}
306 
307 	/* For variadic functions any additional (optional) arguments that were added must be
308 	 * checked against the signature of the variadic argument, so in this case we have to
309 	 * go through all the parameters of the function and not just those present in the
310 	 * prototype. */
311 	num_args = proto->common.num_args;
312 	if (proto->common.fn_flags & ZEND_ACC_VARIADIC) {
313 		num_args++;
314         if (fe->common.num_args >= proto->common.num_args) {
315 			num_args = fe->common.num_args;
316 			if (fe->common.fn_flags & ZEND_ACC_VARIADIC) {
317 				num_args++;
318 			}
319 		}
320 	}
321 
322 	for (i = 0; i < num_args; i++) {
323 		zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
324 
325 		zend_arg_info *proto_arg_info;
326 		if (i < proto->common.num_args) {
327 			proto_arg_info = &proto->common.arg_info[i];
328 		} else {
329 			proto_arg_info = &proto->common.arg_info[proto->common.num_args];
330 		}
331 
332 		if (!zend_do_perform_arg_type_hint_check(fe, fe_arg_info, proto, proto_arg_info)) {
333 			switch (ZEND_TYPE_CODE(fe_arg_info->type)) {
334 				case IS_ITERABLE:
335 					if (!zend_iterable_compatibility_check(proto_arg_info)) {
336 						return 0;
337 					}
338 					break;
339 
340 				default:
341 					return 0;
342 			}
343 		}
344 
345 		// This introduces BC break described at https://bugs.php.net/bug.php?id=72119
346 		if (ZEND_TYPE_IS_SET(proto_arg_info->type) && ZEND_TYPE_ALLOW_NULL(proto_arg_info->type) && !ZEND_TYPE_ALLOW_NULL(fe_arg_info->type)) {
347 			/* incompatible nullability */
348 			return 0;
349 		}
350 
351 		/* by-ref constraints on arguments are invariant */
352 		if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
353 			return 0;
354 		}
355 	}
356 
357 	/* Check return type compatibility, but only if the prototype already specifies
358 	 * a return type. Adding a new return type is always valid. */
359 	if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
360 		/* Removing a return type is not valid. */
361 		if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
362 			return 0;
363 		}
364 
365 		if (!zend_do_perform_type_hint_check(fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1)) {
366 			switch (ZEND_TYPE_CODE(proto->common.arg_info[-1].type)) {
367 				case IS_ITERABLE:
368 					if (!zend_iterable_compatibility_check(fe->common.arg_info - 1)) {
369 						return 0;
370 					}
371 					break;
372 
373 				default:
374 					return 0;
375 			}
376 		}
377 
378 		if (ZEND_TYPE_ALLOW_NULL(fe->common.arg_info[-1].type) && !ZEND_TYPE_ALLOW_NULL(proto->common.arg_info[-1].type)) {
379 			return 0;
380 		}
381 	}
382 	return 1;
383 }
384 /* }}} */
385 
zend_append_type_hint(smart_str * str,const zend_function * fptr,zend_arg_info * arg_info,int return_hint)386 static ZEND_COLD void zend_append_type_hint(smart_str *str, const zend_function *fptr, zend_arg_info *arg_info, int return_hint) /* {{{ */
387 {
388 
389 	if (ZEND_TYPE_IS_SET(arg_info->type) && ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
390 		smart_str_appendc(str, '?');
391 	}
392 
393 	if (ZEND_TYPE_IS_CLASS(arg_info->type)) {
394 		const char *class_name;
395 		size_t class_name_len;
396 
397 		class_name = ZSTR_VAL(ZEND_TYPE_NAME(arg_info->type));
398 		class_name_len = ZSTR_LEN(ZEND_TYPE_NAME(arg_info->type));
399 
400 		if (!strcasecmp(class_name, "self") && fptr->common.scope) {
401 			class_name = ZSTR_VAL(fptr->common.scope->name);
402 			class_name_len = ZSTR_LEN(fptr->common.scope->name);
403 		} else if (!strcasecmp(class_name, "parent") && fptr->common.scope && fptr->common.scope->parent) {
404 			class_name = ZSTR_VAL(fptr->common.scope->parent->name);
405 			class_name_len = ZSTR_LEN(fptr->common.scope->parent->name);
406 		}
407 
408 		smart_str_appendl(str, class_name, class_name_len);
409 		if (!return_hint) {
410 			smart_str_appendc(str, ' ');
411 		}
412 	} else if (ZEND_TYPE_IS_CODE(arg_info->type)) {
413 		if (ZEND_TYPE_CODE(arg_info->type) == IS_LONG) {
414 			smart_str_appendl(str, "int", 3);
415 		} else if (ZEND_TYPE_CODE(arg_info->type) == _IS_BOOL) {
416 			smart_str_appendl(str, "bool", 4);
417 		} else {
418 			const char *type_name = zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type));
419 			smart_str_appends(str, type_name);
420 		}
421 		if (!return_hint) {
422 			smart_str_appendc(str, ' ');
423 		}
424 	}
425 }
426 /* }}} */
427 
zend_get_function_declaration(const zend_function * fptr)428 static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function *fptr) /* {{{ */
429 {
430 	smart_str str = {0};
431 
432 	if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
433 		smart_str_appends(&str, "& ");
434 	}
435 
436 	if (fptr->common.scope) {
437 		/* cut off on NULL byte ... class@anonymous */
438 		smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), strlen(ZSTR_VAL(fptr->common.scope->name)));
439 		smart_str_appends(&str, "::");
440 	}
441 
442 	smart_str_append(&str, fptr->common.function_name);
443 	smart_str_appendc(&str, '(');
444 
445 	if (fptr->common.arg_info) {
446 		uint32_t i, num_args, required;
447 		zend_arg_info *arg_info = fptr->common.arg_info;
448 
449 		required = fptr->common.required_num_args;
450 		num_args = fptr->common.num_args;
451 		if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
452 			num_args++;
453 		}
454 		for (i = 0; i < num_args;) {
455 			zend_append_type_hint(&str, fptr, arg_info, 0);
456 
457 			if (arg_info->pass_by_reference) {
458 				smart_str_appendc(&str, '&');
459 			}
460 
461 			if (arg_info->is_variadic) {
462 				smart_str_appends(&str, "...");
463 			}
464 
465 			smart_str_appendc(&str, '$');
466 
467 			if (arg_info->name) {
468 				if (fptr->type == ZEND_INTERNAL_FUNCTION) {
469 					smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
470 				} else {
471 					smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name));
472 				}
473 			} else {
474 				smart_str_appends(&str, "param");
475 				smart_str_append_unsigned(&str, i);
476 			}
477 
478 			if (i >= required && !arg_info->is_variadic) {
479 				smart_str_appends(&str, " = ");
480 				if (fptr->type == ZEND_USER_FUNCTION) {
481 					zend_op *precv = NULL;
482 					{
483 						uint32_t idx  = i;
484 						zend_op *op = fptr->op_array.opcodes;
485 						zend_op *end = op + fptr->op_array.last;
486 
487 						++idx;
488 						while (op < end) {
489 							if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
490 									&& op->op1.num == (zend_ulong)idx)
491 							{
492 								precv = op;
493 							}
494 							++op;
495 						}
496 					}
497 					if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
498 						zval *zv = RT_CONSTANT(&fptr->op_array, precv->op2);
499 
500 						if (Z_TYPE_P(zv) == IS_CONSTANT) {
501 							smart_str_append(&str, Z_STR_P(zv));
502 						} else if (Z_TYPE_P(zv) == IS_FALSE) {
503 							smart_str_appends(&str, "false");
504 						} else if (Z_TYPE_P(zv) == IS_TRUE) {
505 							smart_str_appends(&str, "true");
506 						} else if (Z_TYPE_P(zv) == IS_NULL) {
507 							smart_str_appends(&str, "NULL");
508 						} else if (Z_TYPE_P(zv) == IS_STRING) {
509 							smart_str_appendc(&str, '\'');
510 							smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
511 							if (Z_STRLEN_P(zv) > 10) {
512 								smart_str_appends(&str, "...");
513 							}
514 							smart_str_appendc(&str, '\'');
515 						} else if (Z_TYPE_P(zv) == IS_ARRAY) {
516 							smart_str_appends(&str, "Array");
517 						} else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
518 							smart_str_appends(&str, "<expression>");
519 						} else {
520 							zend_string *zv_str = zval_get_string(zv);
521 							smart_str_append(&str, zv_str);
522 							zend_string_release(zv_str);
523 						}
524 					}
525 				} else {
526 					smart_str_appends(&str, "NULL");
527 				}
528 			}
529 
530 			if (++i < num_args) {
531 				smart_str_appends(&str, ", ");
532 			}
533 			arg_info++;
534 		}
535 	}
536 
537 	smart_str_appendc(&str, ')');
538 
539 	if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
540 		smart_str_appends(&str, ": ");
541 		zend_append_type_hint(&str, fptr, fptr->common.arg_info - 1, 1);
542 	}
543 	smart_str_0(&str);
544 
545 	return str.s;
546 }
547 /* }}} */
548 
do_inheritance_check_on_method(zend_function * child,zend_function * parent)549 static void do_inheritance_check_on_method(zend_function *child, zend_function *parent) /* {{{ */
550 {
551 	uint32_t child_flags;
552 	uint32_t parent_flags = parent->common.fn_flags;
553 
554 	if (UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
555 		zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
556 	}
557 
558 	child_flags	= child->common.fn_flags;
559 	/* You cannot change from static to non static and vice versa.
560 	 */
561 	if (UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
562 		if (child->common.fn_flags & ZEND_ACC_STATIC) {
563 			zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
564 		} else {
565 			zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
566 		}
567 	}
568 
569 	/* Disallow making an inherited method abstract. */
570 	if (UNEXPECTED((child_flags & ZEND_ACC_ABSTRACT) > (parent_flags & ZEND_ACC_ABSTRACT))) {
571 		zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
572 	}
573 
574 	/* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
575 	if (UNEXPECTED((!(child_flags & ZEND_ACC_CTOR) || (parent_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_IMPLEMENTED_ABSTRACT))) &&
576 		(child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK))) {
577 		zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", 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");
578 	}
579 
580 	if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
581 		&& ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
582 		child->common.fn_flags |= ZEND_ACC_CHANGED;
583 	}
584 	if (parent_flags & ZEND_ACC_CHANGED) {
585 		child->common.fn_flags |= ZEND_ACC_CHANGED;
586 	}
587 
588 	if (parent_flags & ZEND_ACC_PRIVATE) {
589 		child->common.prototype = NULL;
590 	} else if (parent_flags & ZEND_ACC_ABSTRACT) {
591 		child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
592 		child->common.prototype = parent;
593 	} else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
594 		/* ctors only have a prototype if it comes from an interface */
595 		child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
596 		/* and if that is the case, we want to check inheritance against it */
597 		if (parent->common.fn_flags & ZEND_ACC_CTOR) {
598 			parent = child->common.prototype;
599 		}
600 	}
601 
602 	if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) {
603 		int error_level;
604 		const char *error_verb;
605 		zend_string *method_prototype = zend_get_function_declaration(parent);
606 		zend_string *child_prototype = zend_get_function_declaration(child);
607 
608 		if (child->common.prototype && (
609 			child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT
610 		)) {
611 			error_level = E_COMPILE_ERROR;
612 			error_verb = "must";
613 		} else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
614                    (!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
615 		            !zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1) ||
616 		            (ZEND_TYPE_ALLOW_NULL(child->common.arg_info[-1].type) && !ZEND_TYPE_ALLOW_NULL(parent->common.arg_info[-1].type)))) {
617 			error_level = E_COMPILE_ERROR;
618 			error_verb = "must";
619 		} else {
620 			error_level = E_WARNING;
621 			error_verb = "should";
622 		}
623 		zend_error(error_level, "Declaration of %s %s be compatible with %s", ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype));
624 		zend_string_free(child_prototype);
625 		zend_string_free(method_prototype);
626 	}
627 }
628 /* }}} */
629 
do_inherit_method(zend_string * key,zend_function * parent,zend_class_entry * ce)630 static zend_function *do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce) /* {{{ */
631 {
632 	zval *child = zend_hash_find(&ce->function_table, key);
633 
634 	if (child) {
635 		zend_function *func = (zend_function*)Z_PTR_P(child);
636 		zend_function *orig_prototype = func->common.prototype;
637 
638 		do_inheritance_check_on_method(func, parent);
639 		if (func->common.prototype != orig_prototype &&
640 		    func->type == ZEND_USER_FUNCTION &&
641 		    func->common.scope != ce &&
642 		    !func->op_array.static_variables) {
643 			/* Lazy duplication */
644 			zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
645 			memcpy(new_function, func, sizeof(zend_op_array));
646 			Z_PTR_P(child) = new_function;
647 			func->common.prototype = orig_prototype;
648 		}
649 		return NULL;
650 	}
651 
652 	if (parent->common.fn_flags & (ZEND_ACC_ABSTRACT)) {
653 		ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
654 	}
655 
656 	return zend_duplicate_function(parent, ce);
657 }
658 /* }}} */
659 
do_inherit_property(zend_property_info * parent_info,zend_string * key,zend_class_entry * ce)660 static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
661 {
662 	zval *child = zend_hash_find(&ce->properties_info, key);
663 	zend_property_info *child_info;
664 
665 	if (UNEXPECTED(child)) {
666 		child_info = Z_PTR_P(child);
667 		if (UNEXPECTED(parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW))) {
668 			child_info->flags |= ZEND_ACC_CHANGED;
669 		} else {
670 			if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
671 				zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
672 					(parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->parent->name), ZSTR_VAL(key),
673 					(child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
674 			}
675 
676 			if (parent_info->flags & ZEND_ACC_CHANGED) {
677 				child_info->flags |= ZEND_ACC_CHANGED;
678 			}
679 
680 			if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
681 				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");
682 			} else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
683 				int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
684 				int child_num = OBJ_PROP_TO_NUM(child_info->offset);
685 
686 				/* Don't keep default properties in GC (they may be freed by opcache) */
687 				zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
688 				ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
689 				ZVAL_UNDEF(&ce->default_properties_table[child_num]);
690 				child_info->offset = parent_info->offset;
691 			}
692 		}
693 	} else {
694 		if (UNEXPECTED(parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW))) {
695 			if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
696 				child_info = zend_duplicate_property_info_internal(parent_info);
697 			} else {
698 				child_info = zend_duplicate_property_info(parent_info);
699 			}
700 			child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
701 			child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
702 		} else {
703 			if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
704 				child_info = zend_duplicate_property_info_internal(parent_info);
705 			} else {
706 				child_info = parent_info;
707 			}
708 		}
709 		_zend_hash_append_ptr(&ce->properties_info, key, child_info);
710 	}
711 }
712 /* }}} */
713 
do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)714 static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
715 {
716 	if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
717 		zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
718 	}
719 	if (UNEXPECTED(ce == iface)) {
720 		zend_error_noreturn(E_ERROR, "Interface %s cannot implement itself", ZSTR_VAL(ce->name));
721 	}
722 }
723 /* }}} */
724 
zend_do_inherit_interfaces(zend_class_entry * ce,const zend_class_entry * iface)725 ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
726 {
727 	/* expects interface to be contained in ce's interface list already */
728 	uint32_t i, ce_num, if_num = iface->num_interfaces;
729 	zend_class_entry *entry;
730 
731 	if (if_num==0) {
732 		return;
733 	}
734 	ce_num = ce->num_interfaces;
735 
736 	if (ce->type == ZEND_INTERNAL_CLASS) {
737 		ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
738 	} else {
739 		ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
740 	}
741 
742 	/* Inherit the interfaces, only if they're not already inherited by the class */
743 	while (if_num--) {
744 		entry = iface->interfaces[if_num];
745 		for (i = 0; i < ce_num; i++) {
746 			if (ce->interfaces[i] == entry) {
747 				break;
748 			}
749 		}
750 		if (i == ce_num) {
751 			ce->interfaces[ce->num_interfaces++] = entry;
752 		}
753 	}
754 
755 	/* and now call the implementing handlers */
756 	while (ce_num < ce->num_interfaces) {
757 		do_implement_interface(ce, ce->interfaces[ce_num++]);
758 	}
759 }
760 /* }}} */
761 
do_inherit_class_constant(zend_string * name,zend_class_constant * parent_const,zend_class_entry * ce)762 static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
763 {
764 	zend_class_constant *c = zend_hash_find_ptr(&ce->constants_table, name);
765 
766 	if (c != NULL) {
767 		if (UNEXPECTED((Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PPP_MASK) > (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PPP_MASK))) {
768 			zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s",
769 				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");
770 		}
771 	} else if (!(Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PRIVATE)) {
772 		if (Z_CONSTANT(parent_const->value)) {
773 			ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
774 		}
775 		if (ce->type & ZEND_INTERNAL_CLASS) {
776 			if (Z_REFCOUNTED(parent_const->value)) {
777 				Z_ADDREF(parent_const->value);
778 			}
779 			c = pemalloc(sizeof(zend_class_constant), 1);
780 			memcpy(c, parent_const, sizeof(zend_class_constant));
781 		} else {
782 			c = parent_const;
783 		}
784 		_zend_hash_append_ptr(&ce->constants_table, name, c);
785 	}
786 }
787 /* }}} */
788 
zend_do_inheritance(zend_class_entry * ce,zend_class_entry * parent_ce)789 ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
790 {
791 	zend_property_info *property_info;
792 	zend_function *func;
793 	zend_string *key;
794 
795 	if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) {
796 		/* Interface can only inherit other interfaces */
797 		if (UNEXPECTED(!(parent_ce->ce_flags & ZEND_ACC_INTERFACE))) {
798 			zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
799 		}
800 	} else if (UNEXPECTED(parent_ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_FINAL))) {
801 		/* Class declaration must not extend traits or interfaces */
802 		if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
803 			zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
804 		} else if (parent_ce->ce_flags & ZEND_ACC_TRAIT) {
805 			zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
806 		}
807 
808 		/* Class must not extend a final class */
809 		if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
810 			zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
811 		}
812 	}
813 
814 	ce->parent = parent_ce;
815 
816 	/* Inherit interfaces */
817 	zend_do_inherit_interfaces(ce, parent_ce);
818 
819 	/* Inherit properties */
820 	if (parent_ce->default_properties_count) {
821 		zval *src, *dst, *end;
822 
823 		if (ce->default_properties_count) {
824 			zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
825 			src = ce->default_properties_table + ce->default_properties_count;
826 			end = table + parent_ce->default_properties_count;
827 			dst = end + ce->default_properties_count;
828 			ce->default_properties_table = table;
829 			do {
830 				dst--;
831 				src--;
832 				ZVAL_COPY_VALUE(dst, src);
833 			} while (dst != end);
834 			pefree(src, ce->type == ZEND_INTERNAL_CLASS);
835 			end = ce->default_properties_table;
836 		} else {
837 			end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
838 			dst = end + parent_ce->default_properties_count;
839 			ce->default_properties_table = end;
840 		}
841 		src = parent_ce->default_properties_table + parent_ce->default_properties_count;
842 		do {
843 			dst--;
844 			src--;
845 #ifdef ZTS
846 			if (parent_ce->type != ce->type) {
847 				ZVAL_DUP(dst, src);
848 				if (Z_OPT_CONSTANT_P(dst)) {
849 					ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
850 				}
851 				continue;
852 			}
853 #endif
854 
855 			ZVAL_COPY(dst, src);
856 			if (Z_OPT_CONSTANT_P(dst)) {
857 				ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
858 			}
859 		} while (dst != end);
860 		ce->default_properties_count += parent_ce->default_properties_count;
861 	}
862 
863 	if (parent_ce->default_static_members_count) {
864 		zval *src, *dst, *end;
865 
866 		if (ce->default_static_members_count) {
867 			zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
868 			src = ce->default_static_members_table + ce->default_static_members_count;
869 			end = table + parent_ce->default_static_members_count;
870 			dst = end + ce->default_static_members_count;
871 			ce->default_static_members_table = table;
872 			do {
873 				dst--;
874 				src--;
875 				ZVAL_COPY_VALUE(dst, src);
876 			} while (dst != end);
877 			pefree(src, ce->type == ZEND_INTERNAL_CLASS);
878 			end = ce->default_static_members_table;
879 		} else {
880 			end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
881 			dst = end + parent_ce->default_static_members_count;
882 			ce->default_static_members_table = end;
883 		}
884 		src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
885 		do {
886 			dst--;
887 			src--;
888 			if (parent_ce->type == ZEND_INTERNAL_CLASS) {
889 				if (!Z_ISREF_P(src)) {
890 					ZVAL_NEW_PERSISTENT_REF(src, src);
891 				}
892 			} else {
893 				ZVAL_MAKE_REF(src);
894 			}
895 			ZVAL_COPY_VALUE(dst, src);
896 			Z_ADDREF_P(dst);
897 			if (Z_CONSTANT_P(Z_REFVAL_P(dst))) {
898 				ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
899 			}
900 		} while (dst != end);
901 		ce->default_static_members_count += parent_ce->default_static_members_count;
902 		if (ce->type == ZEND_USER_CLASS) {
903 			ce->static_members_table = ce->default_static_members_table;
904 		} else {
905 			ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
906 		}
907 	}
908 
909 	ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
910 		if (property_info->ce == ce) {
911 			if (property_info->flags & ZEND_ACC_STATIC) {
912 				property_info->offset += parent_ce->default_static_members_count;
913 			} else {
914 				property_info->offset += parent_ce->default_properties_count * sizeof(zval);
915 			}
916 		}
917 	} ZEND_HASH_FOREACH_END();
918 
919 	if (zend_hash_num_elements(&parent_ce->properties_info)) {
920 		zend_hash_extend(&ce->properties_info,
921 			zend_hash_num_elements(&ce->properties_info) +
922 			zend_hash_num_elements(&parent_ce->properties_info), 0);
923 
924 		ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
925 			do_inherit_property(property_info, key, ce);
926 		} ZEND_HASH_FOREACH_END();
927 	}
928 
929 	if (zend_hash_num_elements(&parent_ce->constants_table)) {
930 		zend_class_constant *c;
931 
932 		zend_hash_extend(&ce->constants_table,
933 			zend_hash_num_elements(&ce->constants_table) +
934 			zend_hash_num_elements(&parent_ce->constants_table), 0);
935 
936 		ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
937 			do_inherit_class_constant(key, c, ce);
938 		} ZEND_HASH_FOREACH_END();
939 	}
940 
941 	if (zend_hash_num_elements(&parent_ce->function_table)) {
942 		zend_hash_extend(&ce->function_table,
943 			zend_hash_num_elements(&ce->function_table) +
944 			zend_hash_num_elements(&parent_ce->function_table), 0);
945 
946 		ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
947 			zend_function *new_func = do_inherit_method(key, func, ce);
948 
949 			if (new_func) {
950 				_zend_hash_append_ptr(&ce->function_table, key, new_func);
951 			}
952 		} ZEND_HASH_FOREACH_END();
953 	}
954 
955 	do_inherit_parent_constructor(ce);
956 
957 	if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
958 		ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
959 	} else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
960 		/* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
961 		zend_verify_abstract_class(ce);
962 	}
963 	ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_USE_GUARDS);
964 }
965 /* }}} */
966 
do_inherit_constant_check(HashTable * child_constants_table,zend_class_constant * parent_constant,zend_string * name,const zend_class_entry * iface)967 static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zend_class_constant *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
968 {
969 	zend_class_constant *old_constant;
970 
971 	if ((old_constant = zend_hash_find_ptr(child_constants_table, name)) != NULL) {
972 		if (old_constant->ce != parent_constant->ce) {
973 			zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", ZSTR_VAL(name), ZSTR_VAL(iface->name));
974 		}
975 		return 0;
976 	}
977 	return 1;
978 }
979 /* }}} */
980 
do_inherit_iface_constant(zend_string * name,zend_class_constant * c,zend_class_entry * ce,zend_class_entry * iface)981 static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
982 {
983 	if (do_inherit_constant_check(&ce->constants_table, c, name, iface)) {
984 		zend_class_constant *ct;
985 		if (Z_CONSTANT(c->value)) {
986 			ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
987 		}
988 		if (ce->type & ZEND_INTERNAL_CLASS) {
989 			if (Z_REFCOUNTED(c->value)) {
990 				Z_ADDREF(c->value);
991 			}
992 			ct = pemalloc(sizeof(zend_class_constant), 1);
993 			memcpy(ct, c, sizeof(zend_class_constant));
994 		} else {
995 			ct = c;
996 		}
997 		zend_hash_update_ptr(&ce->constants_table, name, ct);
998 	}
999 }
1000 /* }}} */
1001 
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1002 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1003 {
1004 	uint32_t i, ignore = 0;
1005 	uint32_t current_iface_num = ce->num_interfaces;
1006 	uint32_t parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
1007 	zend_function *func;
1008 	zend_string *key;
1009 	zend_class_constant *c;
1010 
1011 	for (i = 0; i < ce->num_interfaces; i++) {
1012 		if (ce->interfaces[i] == NULL) {
1013 			memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
1014 			i--;
1015 		} else if (ce->interfaces[i] == iface) {
1016 			if (EXPECTED(i < parent_iface_num)) {
1017 				ignore = 1;
1018 			} else {
1019 				zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1020 			}
1021 		}
1022 	}
1023 	if (ignore) {
1024 		/* Check for attempt to redeclare interface constants */
1025 		ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
1026 			do_inherit_constant_check(&iface->constants_table, c, key, iface);
1027 		} ZEND_HASH_FOREACH_END();
1028 	} else {
1029 		if (ce->num_interfaces >= current_iface_num) {
1030 			if (ce->type == ZEND_INTERNAL_CLASS) {
1031 				ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1032 			} else {
1033 				ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1034 			}
1035 		}
1036 		ce->interfaces[ce->num_interfaces++] = iface;
1037 
1038 		ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1039 			do_inherit_iface_constant(key, c, ce, iface);
1040 		} ZEND_HASH_FOREACH_END();
1041 
1042 		ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
1043 			zend_function *new_func = do_inherit_method(key, func, ce);
1044 
1045 			if (new_func) {
1046 				zend_hash_add_new_ptr(&ce->function_table, key, new_func);
1047 			}
1048 		} ZEND_HASH_FOREACH_END();
1049 
1050 		do_implement_interface(ce, iface);
1051 		zend_do_inherit_interfaces(ce, iface);
1052 	}
1053 }
1054 /* }}} */
1055 
zend_do_implement_trait(zend_class_entry * ce,zend_class_entry * trait)1056 ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait) /* {{{ */
1057 {
1058 	uint32_t i, ignore = 0;
1059 	uint32_t current_trait_num = ce->num_traits;
1060 	uint32_t parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
1061 
1062 	for (i = 0; i < ce->num_traits; i++) {
1063 		if (ce->traits[i] == NULL) {
1064 			memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
1065 			i--;
1066 		} else if (ce->traits[i] == trait) {
1067 			if (i < parent_trait_num) {
1068 				ignore = 1;
1069 			}
1070 		}
1071 	}
1072 	if (!ignore) {
1073 		if (ce->num_traits >= current_trait_num) {
1074 			if (ce->type == ZEND_INTERNAL_CLASS) {
1075 				ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1076 			} else {
1077 				ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1078 			}
1079 		}
1080 		ce->traits[ce->num_traits++] = trait;
1081 	}
1082 }
1083 /* }}} */
1084 
zend_traits_method_compatibility_check(zend_function * fn,zend_function * other_fn)1085 static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn) /* {{{ */
1086 {
1087 	uint32_t    fn_flags = fn->common.scope->ce_flags;
1088 	uint32_t other_flags = other_fn->common.scope->ce_flags;
1089 
1090 	return zend_do_perform_implementation_check(fn, other_fn)
1091 		&& ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
1092 		    (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
1093 }
1094 /* }}} */
1095 
zend_add_magic_methods(zend_class_entry * ce,zend_string * mname,zend_function * fe)1096 static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe) /* {{{ */
1097 {
1098 	if (zend_string_equals_literal(mname, ZEND_CLONE_FUNC_NAME)) {
1099 		ce->clone = fe;
1100 	} else if (zend_string_equals_literal(mname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
1101 		if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
1102 			zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name));
1103 		}
1104 		ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
1105 	} else if (zend_string_equals_literal(mname, ZEND_DESTRUCTOR_FUNC_NAME)) {
1106 		ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
1107 	} else if (zend_string_equals_literal(mname, ZEND_GET_FUNC_NAME)) {
1108 		ce->__get = fe;
1109 		ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1110 	} else if (zend_string_equals_literal(mname, ZEND_SET_FUNC_NAME)) {
1111 		ce->__set = fe;
1112 		ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1113 	} else if (zend_string_equals_literal(mname, ZEND_CALL_FUNC_NAME)) {
1114 		ce->__call = fe;
1115 	} else if (zend_string_equals_literal(mname, ZEND_UNSET_FUNC_NAME)) {
1116 		ce->__unset = fe;
1117 		ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1118 	} else if (zend_string_equals_literal(mname, ZEND_ISSET_FUNC_NAME)) {
1119 		ce->__isset = fe;
1120 		ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1121 	} else if (zend_string_equals_literal(mname, ZEND_CALLSTATIC_FUNC_NAME)) {
1122 		ce->__callstatic = fe;
1123 	} else if (zend_string_equals_literal(mname, ZEND_TOSTRING_FUNC_NAME)) {
1124 		ce->__tostring = fe;
1125 	} else if (zend_string_equals_literal(mname, ZEND_DEBUGINFO_FUNC_NAME)) {
1126 		ce->__debugInfo = fe;
1127 	} else if (ZSTR_LEN(ce->name) == ZSTR_LEN(mname)) {
1128 		zend_string *lowercase_name = zend_string_tolower(ce->name);
1129 		lowercase_name = zend_new_interned_string(lowercase_name);
1130 		if (!memcmp(ZSTR_VAL(mname), ZSTR_VAL(lowercase_name), ZSTR_LEN(mname))) {
1131 			if (ce->constructor  && (!ce->parent || ce->constructor != ce->parent->constructor)) {
1132 				zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name));
1133 			}
1134 			ce->constructor = fe;
1135 			fe->common.fn_flags |= ZEND_ACC_CTOR;
1136 		}
1137 		zend_string_release(lowercase_name);
1138 	}
1139 }
1140 /* }}} */
1141 
zend_add_trait_method(zend_class_entry * ce,const char * name,zend_string * key,zend_function * fn,HashTable ** overriden)1142 static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overriden) /* {{{ */
1143 {
1144 	zend_function *existing_fn = NULL;
1145 	zend_function *new_fn;
1146 
1147 	if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
1148 		if (existing_fn->common.scope == ce) {
1149 			/* members from the current class override trait methods */
1150 			/* use temporary *overriden HashTable to detect hidden conflict */
1151 			if (*overriden) {
1152 				if ((existing_fn = zend_hash_find_ptr(*overriden, key)) != NULL) {
1153 					if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1154 						/* Make sure the trait method is compatible with previosly declared abstract method */
1155 						if (UNEXPECTED(!zend_traits_method_compatibility_check(fn, existing_fn))) {
1156 							zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1157 								ZSTR_VAL(zend_get_function_declaration(fn)),
1158 								ZSTR_VAL(zend_get_function_declaration(existing_fn)));
1159 						}
1160 					}
1161 					if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1162 						/* Make sure the abstract declaration is compatible with previous declaration */
1163 						if (UNEXPECTED(!zend_traits_method_compatibility_check(existing_fn, fn))) {
1164 							zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1165 								ZSTR_VAL(zend_get_function_declaration(existing_fn)),
1166 								ZSTR_VAL(zend_get_function_declaration(fn)));
1167 						}
1168 						return;
1169 					}
1170 				}
1171 			} else {
1172 				ALLOC_HASHTABLE(*overriden);
1173 				zend_hash_init_ex(*overriden, 8, NULL, overriden_ptr_dtor, 0, 0);
1174 			}
1175 			zend_hash_update_mem(*overriden, key, fn, sizeof(zend_function));
1176 			return;
1177 		} else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT &&
1178 				(existing_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0) {
1179 			/* Make sure the trait method is compatible with previosly declared abstract method */
1180 			if (UNEXPECTED(!zend_traits_method_compatibility_check(fn, existing_fn))) {
1181 				zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1182 					ZSTR_VAL(zend_get_function_declaration(fn)),
1183 					ZSTR_VAL(zend_get_function_declaration(existing_fn)));
1184 			}
1185 		} else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1186 			/* Make sure the abstract declaration is compatible with previous declaration */
1187 			if (UNEXPECTED(!zend_traits_method_compatibility_check(existing_fn, fn))) {
1188 				zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1189 					ZSTR_VAL(zend_get_function_declaration(existing_fn)),
1190 					ZSTR_VAL(zend_get_function_declaration(fn)));
1191 			}
1192 			return;
1193 		} else if (UNEXPECTED(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
1194 			/* two traits can't define the same non-abstract method */
1195 #if 1
1196 			zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
1197 				name, ZSTR_VAL(ce->name));
1198 #else		/* TODO: better error message */
1199 			zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
1200 				ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
1201 				ZSTR_VAL(ce->name), name,
1202 				ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
1203 #endif
1204 		} else {
1205 			/* inherited members are overridden by members inserted by traits */
1206 			/* check whether the trait method fulfills the inheritance requirements */
1207 			do_inheritance_check_on_method(fn, existing_fn);
1208 			fn->common.prototype = NULL;
1209 		}
1210 	}
1211 
1212 	function_add_ref(fn);
1213 	if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
1214 		new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
1215 		memcpy(new_fn, fn, sizeof(zend_internal_function));
1216 		new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
1217 	} else {
1218 		new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1219 		memcpy(new_fn, fn, sizeof(zend_op_array));
1220 	}
1221 	fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
1222 	zend_add_magic_methods(ce, key, fn);
1223 }
1224 /* }}} */
1225 
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce)1226 static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
1227 {
1228 	if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1229 
1230 		fn->common.scope = ce;
1231 
1232 		if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1233 			ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1234 		}
1235 		if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
1236 			ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
1237 		}
1238 	}
1239 }
1240 /* }}} */
1241 
zend_traits_copy_functions(zend_string * fnname,zend_function * fn,zend_class_entry * ce,HashTable ** overriden,HashTable * exclude_table)1242 static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table) /* {{{ */
1243 {
1244 	zend_trait_alias  *alias, **alias_ptr;
1245 	zend_string       *lcname;
1246 	zend_function      fn_copy;
1247 
1248 	/* apply aliases which are qualified with a class name, there should not be any ambiguity */
1249 	if (ce->trait_aliases) {
1250 		alias_ptr = ce->trait_aliases;
1251 		alias = *alias_ptr;
1252 		while (alias) {
1253 			/* Scope unset or equal to the function we compare to, and the alias applies to fn */
1254 			if (alias->alias != NULL
1255 				&& (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
1256 				&& ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname)
1257 				&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
1258 				fn_copy = *fn;
1259 
1260 				/* if it is 0, no modifieres has been changed */
1261 				if (alias->modifiers) {
1262 					fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1263 				}
1264 
1265 				lcname = zend_string_tolower(alias->alias);
1266 				zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overriden);
1267 				zend_string_release(lcname);
1268 
1269 				/* Record the trait from which this alias was resolved. */
1270 				if (!alias->trait_method->ce) {
1271 					alias->trait_method->ce = fn->common.scope;
1272 				}
1273 			}
1274 			alias_ptr++;
1275 			alias = *alias_ptr;
1276 		}
1277 	}
1278 
1279 	if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
1280 		/* is not in hashtable, thus, function is not to be excluded */
1281 		/* And how about ZEND_OVERLOADED_FUNCTION? */
1282 		memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION? sizeof(zend_op_array) : sizeof(zend_internal_function));
1283 
1284 		/* apply aliases which have not alias name, just setting visibility */
1285 		if (ce->trait_aliases) {
1286 			alias_ptr = ce->trait_aliases;
1287 			alias = *alias_ptr;
1288 			while (alias) {
1289 				/* Scope unset or equal to the function we compare to, and the alias applies to fn */
1290 				if (alias->alias == NULL && alias->modifiers != 0
1291 					&& (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
1292 					&& (ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname))
1293 					&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
1294 
1295 					fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1296 
1297 					/** Record the trait from which this alias was resolved. */
1298 					if (!alias->trait_method->ce) {
1299 						alias->trait_method->ce = fn->common.scope;
1300 					}
1301 				}
1302 				alias_ptr++;
1303 				alias = *alias_ptr;
1304 			}
1305 		}
1306 
1307 		zend_add_trait_method(ce, ZSTR_VAL(fn->common.function_name), fnname, &fn_copy, overriden);
1308 	}
1309 
1310 	return ZEND_HASH_APPLY_KEEP;
1311 }
1312 /* }}} */
1313 
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait)1314 static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait) /* {{{ */
1315 {
1316 	uint32_t i;
1317 
1318 	if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
1319 		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));
1320 	}
1321 
1322 	for (i = 0; i < ce->num_traits; i++) {
1323 		if (ce->traits[i] == trait) {
1324 			return;
1325 		}
1326 	}
1327 	zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
1328 }
1329 /* }}} */
1330 
zend_traits_init_trait_structures(zend_class_entry * ce)1331 static void zend_traits_init_trait_structures(zend_class_entry *ce) /* {{{ */
1332 {
1333 	size_t i, j = 0;
1334 	zend_trait_precedence **precedences;
1335 	zend_trait_precedence *cur_precedence;
1336 	zend_trait_method_reference *cur_method_ref;
1337 	zend_string *lcname;
1338 	zend_bool method_exists;
1339 
1340 	/* resolve class references */
1341 	if (ce->trait_precedences) {
1342 		i = 0;
1343 		precedences = ce->trait_precedences;
1344 		ce->trait_precedences = NULL;
1345 		while ((cur_precedence = precedences[i])) {
1346 			/** Resolve classes for all precedence operations. */
1347 			if (cur_precedence->exclude_from_classes) {
1348 				cur_method_ref = cur_precedence->trait_method;
1349 				if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,
1350 								ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD))) {
1351 					zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
1352 				}
1353 				zend_check_trait_usage(ce, cur_precedence->trait_method->ce);
1354 
1355 				/** Ensure that the preferred method is actually available. */
1356 				lcname = zend_string_tolower(cur_method_ref->method_name);
1357 				method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
1358 												 lcname);
1359 				zend_string_release(lcname);
1360 				if (!method_exists) {
1361 					zend_error_noreturn(E_COMPILE_ERROR,
1362 							   "A precedence rule was defined for %s::%s but this method does not exist",
1363 							   ZSTR_VAL(cur_method_ref->ce->name),
1364 							   ZSTR_VAL(cur_method_ref->method_name));
1365 				}
1366 
1367 				/** With the other traits, we are more permissive.
1368 					We do not give errors for those. This allows to be more
1369 					defensive in such definitions.
1370 					However, we want to make sure that the insteadof declaration
1371 					is consistent in itself.
1372 				 */
1373 				j = 0;
1374 				while (cur_precedence->exclude_from_classes[j].class_name) {
1375 					zend_string* class_name = cur_precedence->exclude_from_classes[j].class_name;
1376 
1377 					if (!(cur_precedence->exclude_from_classes[j].ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD))) {
1378 						zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
1379 					}
1380 					zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce);
1381 
1382 					/* make sure that the trait method is not from a class mentioned in
1383 					 exclude_from_classes, for consistency */
1384 					if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[j].ce) {
1385 						zend_error_noreturn(E_COMPILE_ERROR,
1386 								   "Inconsistent insteadof definition. "
1387 								   "The method %s is to be used from %s, but %s is also on the exclude list",
1388 								   ZSTR_VAL(cur_method_ref->method_name),
1389 								   ZSTR_VAL(cur_precedence->trait_method->ce->name),
1390 								   ZSTR_VAL(cur_precedence->trait_method->ce->name));
1391 					}
1392 
1393 					zend_string_release(class_name);
1394 					j++;
1395 				}
1396 			}
1397 			i++;
1398 		}
1399 		ce->trait_precedences = precedences;
1400 	}
1401 
1402 	if (ce->trait_aliases) {
1403 		i = 0;
1404 		while (ce->trait_aliases[i]) {
1405 			/** For all aliases with an explicit class name, resolve the class now. */
1406 			if (ce->trait_aliases[i]->trait_method->class_name) {
1407 				cur_method_ref = ce->trait_aliases[i]->trait_method;
1408 				if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD))) {
1409 					zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
1410 				}
1411 				zend_check_trait_usage(ce, cur_method_ref->ce);
1412 
1413 				/** And, ensure that the referenced method is resolvable, too. */
1414 				lcname = zend_string_tolower(cur_method_ref->method_name);
1415 				method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
1416 						lcname);
1417 				zend_string_release(lcname);
1418 
1419 				if (!method_exists) {
1420 					zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(cur_method_ref->ce->name), ZSTR_VAL(cur_method_ref->method_name));
1421 				}
1422 			}
1423 			i++;
1424 		}
1425 	}
1426 }
1427 /* }}} */
1428 
zend_traits_compile_exclude_table(HashTable * exclude_table,zend_trait_precedence ** precedences,zend_class_entry * trait)1429 static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
1430 {
1431 	size_t i = 0, j;
1432 
1433 	if (!precedences) {
1434 		return;
1435 	}
1436 	while (precedences[i]) {
1437 		if (precedences[i]->exclude_from_classes) {
1438 			j = 0;
1439 			while (precedences[i]->exclude_from_classes[j].ce) {
1440 				if (precedences[i]->exclude_from_classes[j].ce == trait) {
1441 					zend_string *lcname =
1442 						zend_string_tolower(precedences[i]->trait_method->method_name);
1443 					if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
1444 						zend_string_release(lcname);
1445 						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(trait->name));
1446 					}
1447 					zend_string_release(lcname);
1448 				}
1449 				++j;
1450 			}
1451 		}
1452 		++i;
1453 	}
1454 }
1455 /* }}} */
1456 
zend_do_traits_method_binding(zend_class_entry * ce)1457 static void zend_do_traits_method_binding(zend_class_entry *ce) /* {{{ */
1458 {
1459 	uint32_t i;
1460 	HashTable *overriden = NULL;
1461 	zend_string *key;
1462 	zend_function *fn;
1463 
1464 	for (i = 0; i < ce->num_traits; i++) {
1465 		if (ce->trait_precedences) {
1466 			HashTable exclude_table;
1467 			zend_trait_precedence **precedences;
1468 
1469 			/* TODO: revisit this start size, may be its not optimal */
1470 			zend_hash_init_ex(&exclude_table, 8, NULL, NULL, 0, 0);
1471 
1472 			precedences = ce->trait_precedences;
1473 			ce->trait_precedences = NULL;
1474 			zend_traits_compile_exclude_table(&exclude_table, precedences, ce->traits[i]);
1475 
1476 			/* copies functions, applies defined aliasing, and excludes unused trait methods */
1477 			ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
1478 				zend_traits_copy_functions(key, fn, ce, &overriden, &exclude_table);
1479 			} ZEND_HASH_FOREACH_END();
1480 
1481 			zend_hash_destroy(&exclude_table);
1482 			ce->trait_precedences = precedences;
1483 		} else {
1484 			ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
1485 				zend_traits_copy_functions(key, fn, ce, &overriden, NULL);
1486 			} ZEND_HASH_FOREACH_END();
1487 		}
1488 	}
1489 
1490 	ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
1491 		zend_fixup_trait_method(fn, ce);
1492 	} ZEND_HASH_FOREACH_END();
1493 
1494 	if (ce->trait_precedences) {
1495 		i = 0;
1496 		while (ce->trait_precedences[i]) {
1497 			if (ce->trait_precedences[i]->exclude_from_classes) {
1498 				efree(ce->trait_precedences[i]->exclude_from_classes);
1499 				ce->trait_precedences[i]->exclude_from_classes = NULL;
1500 			}
1501 			i++;
1502 		}
1503 	}
1504 
1505 	if (overriden) {
1506 		zend_hash_destroy(overriden);
1507 		FREE_HASHTABLE(overriden);
1508 	}
1509 }
1510 /* }}} */
1511 
find_first_definition(zend_class_entry * ce,size_t current_trait,zend_string * prop_name,zend_class_entry * coliding_ce)1512 static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
1513 {
1514 	size_t i;
1515 
1516 	if (coliding_ce == ce) {
1517 		for (i = 0; i < current_trait; i++) {
1518 			if (zend_hash_exists(&ce->traits[i]->properties_info, prop_name)) {
1519 				return ce->traits[i];
1520 			}
1521 		}
1522 	}
1523 
1524 	return coliding_ce;
1525 }
1526 /* }}} */
1527 
zend_do_traits_property_binding(zend_class_entry * ce)1528 static void zend_do_traits_property_binding(zend_class_entry *ce) /* {{{ */
1529 {
1530 	size_t i;
1531 	zend_property_info *property_info;
1532 	zend_property_info *coliding_prop;
1533 	zend_string* prop_name;
1534 	const char* class_name_unused;
1535 	zend_bool not_compatible;
1536 	zval* prop_value;
1537 	uint32_t flags;
1538 	zend_string *doc_comment;
1539 
1540 	/* In the following steps the properties are inserted into the property table
1541 	 * for that, a very strict approach is applied:
1542 	 * - check for compatibility, if not compatible with any property in class -> fatal
1543 	 * - if compatible, then strict notice
1544 	 */
1545 	for (i = 0; i < ce->num_traits; i++) {
1546 		ZEND_HASH_FOREACH_PTR(&ce->traits[i]->properties_info, property_info) {
1547 			/* first get the unmangeld name if necessary,
1548 			 * then check whether the property is already there
1549 			 */
1550 			flags = property_info->flags;
1551 			if (flags & ZEND_ACC_PUBLIC) {
1552 				prop_name = zend_string_copy(property_info->name);
1553 			} else {
1554 				const char *pname;
1555 				size_t pname_len;
1556 
1557 				/* for private and protected we need to unmangle the names */
1558 				zend_unmangle_property_name_ex(property_info->name,
1559 											&class_name_unused, &pname, &pname_len);
1560 				prop_name = zend_string_init(pname, pname_len, 0);
1561 			}
1562 
1563 			/* next: check for conflicts with current class */
1564 			if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
1565 				if (coliding_prop->flags & ZEND_ACC_SHADOW) {
1566 					zend_string_release(coliding_prop->name);
1567 					if (coliding_prop->doc_comment) {
1568 						zend_string_release(coliding_prop->doc_comment);
1569                     }
1570 					zend_hash_del(&ce->properties_info, prop_name);
1571 					flags |= ZEND_ACC_CHANGED;
1572 				} else {
1573 					if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
1574 						== (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
1575 						/* flags are identical, now the value needs to be checked */
1576 						zval *op1, *op2;
1577 						if (flags & ZEND_ACC_STATIC) {
1578 							op1 = &ce->default_static_members_table[coliding_prop->offset];
1579 							op2 = &ce->traits[i]->default_static_members_table[property_info->offset];
1580 							ZVAL_DEREF(op1);
1581 							ZVAL_DEREF(op2);
1582 						} else {
1583 							op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(coliding_prop->offset)];
1584 							op2 = &ce->traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
1585 						}
1586 						not_compatible = fast_is_not_identical_function(op1, op2);
1587 					} else {
1588 						/* the flags are not identical, thus, we assume properties are not compatible */
1589 						not_compatible = 1;
1590 					}
1591 
1592 					if (not_compatible) {
1593 						zend_error_noreturn(E_COMPILE_ERROR,
1594 							   "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
1595 								ZSTR_VAL(find_first_definition(ce, i, prop_name, coliding_prop->ce)->name),
1596 								ZSTR_VAL(property_info->ce->name),
1597 								ZSTR_VAL(prop_name),
1598 								ZSTR_VAL(ce->name));
1599 					}
1600 
1601 					zend_string_release(prop_name);
1602 					continue;
1603 				}
1604 			}
1605 
1606 			/* property not found, so lets add it */
1607 			if (flags & ZEND_ACC_STATIC) {
1608 				prop_value = &ce->traits[i]->default_static_members_table[property_info->offset];
1609 			} else {
1610 				prop_value = &ce->traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
1611 			}
1612 			if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value);
1613 
1614 			doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
1615 			zend_declare_property_ex(ce, prop_name,
1616 									 prop_value, flags,
1617 								     doc_comment);
1618 			zend_string_release(prop_name);
1619 		} ZEND_HASH_FOREACH_END();
1620 	}
1621 }
1622 /* }}} */
1623 
zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry * ce)1624 static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce) /* {{{ */
1625 {
1626 	int i = 0;
1627 	zend_trait_alias* cur_alias;
1628 	zend_string* lc_method_name;
1629 
1630 	if (ce->trait_aliases) {
1631 		while (ce->trait_aliases[i]) {
1632 			cur_alias = ce->trait_aliases[i];
1633 			/** The trait for this alias has not been resolved, this means, this
1634 				alias was not applied. Abort with an error. */
1635 			if (!cur_alias->trait_method->ce) {
1636 				if (cur_alias->alias) {
1637 					/** Plain old inconsistency/typo/bug */
1638 					zend_error_noreturn(E_COMPILE_ERROR,
1639 							   "An alias (%s) was defined for method %s(), but this method does not exist",
1640 							   ZSTR_VAL(cur_alias->alias),
1641 							   ZSTR_VAL(cur_alias->trait_method->method_name));
1642 				} else {
1643 					/** Here are two possible cases:
1644 						1) this is an attempt to modifiy the visibility
1645 						   of a method introduce as part of another alias.
1646 						   Since that seems to violate the DRY principle,
1647 						   we check against it and abort.
1648 						2) it is just a plain old inconsitency/typo/bug
1649 						   as in the case where alias is set. */
1650 
1651 					lc_method_name = zend_string_tolower(
1652 						cur_alias->trait_method->method_name);
1653 					if (zend_hash_exists(&ce->function_table,
1654 										 lc_method_name)) {
1655 						zend_string_release(lc_method_name);
1656 						zend_error_noreturn(E_COMPILE_ERROR,
1657 								   "The modifiers for the trait alias %s() need to be changed in the same statement in which the alias is defined. Error",
1658 								   ZSTR_VAL(cur_alias->trait_method->method_name));
1659 					} else {
1660 						zend_string_release(lc_method_name);
1661 						zend_error_noreturn(E_COMPILE_ERROR,
1662 								   "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
1663 								   ZSTR_VAL(cur_alias->trait_method->method_name));
1664 
1665 					}
1666 				}
1667 			}
1668 			i++;
1669 		}
1670 	}
1671 }
1672 /* }}} */
1673 
zend_do_bind_traits(zend_class_entry * ce)1674 ZEND_API void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */
1675 {
1676 
1677 	if (ce->num_traits <= 0) {
1678 		return;
1679 	}
1680 
1681 	/* complete initialization of trait strutures in ce */
1682 	zend_traits_init_trait_structures(ce);
1683 
1684 	/* first care about all methods to be flattened into the class */
1685 	zend_do_traits_method_binding(ce);
1686 
1687 	/* Aliases which have not been applied indicate typos/bugs. */
1688 	zend_do_check_for_inconsistent_traits_aliasing(ce);
1689 
1690 	/* then flatten the properties into it, to, mostly to notfiy developer about problems */
1691 	zend_do_traits_property_binding(ce);
1692 
1693 	/* verify that all abstract methods from traits have been implemented */
1694 	zend_verify_abstract_class(ce);
1695 
1696 	/* Emit E_DEPRECATED for PHP 4 constructors */
1697 	zend_check_deprecated_constructor(ce);
1698 
1699 	/* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
1700 	if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1701 		ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1702 	}
1703 }
1704 /* }}} */
1705 
1706 
zend_has_deprecated_constructor(const zend_class_entry * ce)1707 static zend_bool zend_has_deprecated_constructor(const zend_class_entry *ce) /* {{{ */
1708 {
1709 	const zend_string *constructor_name;
1710 	if (!ce->constructor) {
1711 		return 0;
1712 	}
1713 	constructor_name = ce->constructor->common.function_name;
1714 	return !zend_binary_strcasecmp(
1715 		ZSTR_VAL(ce->name), ZSTR_LEN(ce->name),
1716 		ZSTR_VAL(constructor_name), ZSTR_LEN(constructor_name)
1717 	);
1718 }
1719 /* }}} */
1720 
zend_check_deprecated_constructor(const zend_class_entry * ce)1721 void zend_check_deprecated_constructor(const zend_class_entry *ce) /* {{{ */
1722 {
1723 	if (zend_has_deprecated_constructor(ce)) {
1724 		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));
1725 	}
1726 }
1727 /* }}} */
1728 
1729 /*
1730  * Local variables:
1731  * tab-width: 4
1732  * c-basic-offset: 4
1733  * indent-tabs-mode: t
1734  * End:
1735  * vim600: sw=4 ts=4 fdm=marker
1736  * vim<600: sw=4 ts=4
1737  */
1738