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