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