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