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