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