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