1/* 2 +----------------------------------------------------------------------+ 3 | Zend Engine | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1998-2013 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/* $Id$ */ 21 22#include <zend_language_parser.h> 23#include "zend.h" 24#include "zend_compile.h" 25#include "zend_constants.h" 26#include "zend_llist.h" 27#include "zend_API.h" 28#include "zend_exceptions.h" 29#include "tsrm_virtual_cwd.h" 30#include "zend_multibyte.h" 31#include "zend_language_scanner.h" 32 33#define CONSTANT_EX(op_array, op) \ 34 (op_array)->literals[op].constant 35 36#define CONSTANT(op) \ 37 CONSTANT_EX(CG(active_op_array), op) 38 39#define SET_NODE(target, src) do { \ 40 target ## _type = (src)->op_type; \ 41 if ((src)->op_type == IS_CONST) { \ 42 target.constant = zend_add_literal(CG(active_op_array), &(src)->u.constant TSRMLS_CC); \ 43 } else { \ 44 target = (src)->u.op; \ 45 } \ 46 } while (0) 47 48#define GET_NODE(target, src) do { \ 49 (target)->op_type = src ## _type; \ 50 if ((target)->op_type == IS_CONST) { \ 51 (target)->u.constant = CONSTANT(src.constant); \ 52 } else { \ 53 (target)->u.op = src; \ 54 (target)->EA = 0; \ 55 } \ 56 } while (0) 57 58#define COPY_NODE(target, src) do { \ 59 target ## _type = src ## _type; \ 60 target = src; \ 61 } while (0) 62 63#define CALCULATE_LITERAL_HASH(num) do { \ 64 if (IS_INTERNED(Z_STRVAL(CONSTANT(num)))) { \ 65 Z_HASH_P(&CONSTANT(num)) = INTERNED_HASH(Z_STRVAL(CONSTANT(num))); \ 66 } else { \ 67 Z_HASH_P(&CONSTANT(num)) = zend_hash_func(Z_STRVAL(CONSTANT(num)), Z_STRLEN(CONSTANT(num))+1); \ 68 } \ 69 } while (0) 70 71#define GET_CACHE_SLOT(literal) do { \ 72 CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot++; \ 73 if ((CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) && CG(active_op_array)->run_time_cache) { \ 74 CG(active_op_array)->run_time_cache = erealloc(CG(active_op_array)->run_time_cache, CG(active_op_array)->last_cache_slot * sizeof(void*)); \ 75 CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 1] = NULL; \ 76 } \ 77 } while (0) 78 79#define POLYMORPHIC_CACHE_SLOT_SIZE 2 80 81#define GET_POLYMORPHIC_CACHE_SLOT(literal) do { \ 82 CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot; \ 83 CG(active_op_array)->last_cache_slot += POLYMORPHIC_CACHE_SLOT_SIZE; \ 84 if ((CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) && CG(active_op_array)->run_time_cache) { \ 85 CG(active_op_array)->run_time_cache = erealloc(CG(active_op_array)->run_time_cache, CG(active_op_array)->last_cache_slot * sizeof(void*)); \ 86 CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 1] = NULL; \ 87 CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 2] = NULL; \ 88 } \ 89 } while (0) 90 91#define FREE_POLYMORPHIC_CACHE_SLOT(literal) do { \ 92 if (CG(active_op_array)->literals[literal].cache_slot != -1 && \ 93 CG(active_op_array)->literals[literal].cache_slot == \ 94 CG(active_op_array)->last_cache_slot - POLYMORPHIC_CACHE_SLOT_SIZE) { \ 95 CG(active_op_array)->literals[literal].cache_slot = -1; \ 96 CG(active_op_array)->last_cache_slot -= POLYMORPHIC_CACHE_SLOT_SIZE; \ 97 } \ 98 } while (0) 99 100ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); 101ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC); 102 103#ifndef ZTS 104ZEND_API zend_compiler_globals compiler_globals; 105ZEND_API zend_executor_globals executor_globals; 106#endif 107 108static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */ 109{ 110 if (!IS_INTERNED(property_info->name)) { 111 property_info->name = estrndup(property_info->name, property_info->name_length); 112 } 113 if (property_info->doc_comment) { 114 property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len); 115 } 116} 117/* }}} */ 118 119static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */ 120{ 121 if (!IS_INTERNED(property_info->name)) { 122 property_info->name = zend_strndup(property_info->name, property_info->name_length); 123 } 124} 125/* }}} */ 126 127static void zend_destroy_property_info(zend_property_info *property_info) /* {{{ */ 128{ 129 str_efree(property_info->name); 130 if (property_info->doc_comment) { 131 efree((char*)property_info->doc_comment); 132 } 133} 134/* }}} */ 135 136static void zend_destroy_property_info_internal(zend_property_info *property_info) /* {{{ */ 137{ 138 str_free((char*)property_info->name); 139} 140/* }}} */ 141 142static void build_runtime_defined_function_key(zval *result, const char *name, int name_length TSRMLS_DC) /* {{{ */ 143{ 144 char char_pos_buf[32]; 145 uint char_pos_len; 146 const char *filename; 147 148 char_pos_len = zend_sprintf(char_pos_buf, "%p", LANG_SCNG(yy_text)); 149 if (CG(active_op_array)->filename) { 150 filename = CG(active_op_array)->filename; 151 } else { 152 filename = "-"; 153 } 154 155 /* NULL, name length, filename length, last accepting char position length */ 156 result->value.str.len = 1+name_length+strlen(filename)+char_pos_len; 157 158 /* must be binary safe */ 159 result->value.str.val = (char *) safe_emalloc(result->value.str.len, 1, 1); 160 result->value.str.val[0] = '\0'; 161 sprintf(result->value.str.val+1, "%s%s%s", name, filename, char_pos_buf); 162 163 result->type = IS_STRING; 164 Z_SET_REFCOUNT_P(result, 1); 165} 166/* }}} */ 167 168static void init_compiler_declarables(TSRMLS_D) /* {{{ */ 169{ 170 Z_TYPE(CG(declarables).ticks) = IS_LONG; 171 Z_LVAL(CG(declarables).ticks) = 0; 172} 173/* }}} */ 174 175void zend_init_compiler_context(TSRMLS_D) /* {{{ */ 176{ 177 CG(context).opcodes_size = (CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) ? INITIAL_INTERACTIVE_OP_ARRAY_SIZE : INITIAL_OP_ARRAY_SIZE; 178 CG(context).vars_size = 0; 179 CG(context).literals_size = 0; 180 CG(context).current_brk_cont = -1; 181 CG(context).backpatch_count = 0; 182 CG(context).nested_calls = 0; 183 CG(context).used_stack = 0; 184 CG(context).in_finally = 0; 185 CG(context).labels = NULL; 186} 187/* }}} */ 188 189void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */ 190{ 191 zend_stack_init(&CG(bp_stack)); 192 zend_stack_init(&CG(function_call_stack)); 193 zend_stack_init(&CG(switch_cond_stack)); 194 zend_stack_init(&CG(foreach_copy_stack)); 195 zend_stack_init(&CG(object_stack)); 196 zend_stack_init(&CG(declare_stack)); 197 CG(active_class_entry) = NULL; 198 zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0); 199 zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0); 200 zend_stack_init(&CG(list_stack)); 201 CG(in_compilation) = 0; 202 CG(start_lineno) = 0; 203 CG(current_namespace) = NULL; 204 CG(in_namespace) = 0; 205 CG(has_bracketed_namespaces) = 0; 206 CG(current_import) = NULL; 207 init_compiler_declarables(TSRMLS_C); 208 zend_stack_init(&CG(context_stack)); 209 210 CG(encoding_declared) = 0; 211} 212/* }}} */ 213 214ZEND_API void file_handle_dtor(zend_file_handle *fh) /* {{{ */ 215{ 216 TSRMLS_FETCH(); 217 218 zend_file_handle_dtor(fh TSRMLS_CC); 219} 220/* }}} */ 221 222void init_compiler(TSRMLS_D) /* {{{ */ 223{ 224 CG(active_op_array) = NULL; 225 memset(&CG(context), 0, sizeof(CG(context))); 226 zend_init_compiler_data_structures(TSRMLS_C); 227 zend_init_rsrc_list(TSRMLS_C); 228 zend_hash_init(&CG(filenames_table), 5, NULL, (dtor_func_t) free_estring, 0); 229 zend_llist_init(&CG(open_files), sizeof(zend_file_handle), (void (*)(void *)) file_handle_dtor, 0); 230 CG(unclean_shutdown) = 0; 231} 232/* }}} */ 233 234void shutdown_compiler(TSRMLS_D) /* {{{ */ 235{ 236 zend_stack_destroy(&CG(bp_stack)); 237 zend_stack_destroy(&CG(function_call_stack)); 238 zend_stack_destroy(&CG(switch_cond_stack)); 239 zend_stack_destroy(&CG(foreach_copy_stack)); 240 zend_stack_destroy(&CG(object_stack)); 241 zend_stack_destroy(&CG(declare_stack)); 242 zend_stack_destroy(&CG(list_stack)); 243 zend_hash_destroy(&CG(filenames_table)); 244 zend_llist_destroy(&CG(open_files)); 245 zend_stack_destroy(&CG(context_stack)); 246} 247/* }}} */ 248 249ZEND_API char *zend_set_compiled_filename(const char *new_compiled_filename TSRMLS_DC) /* {{{ */ 250{ 251 char **pp, *p; 252 int length = strlen(new_compiled_filename); 253 254 if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) { 255 CG(compiled_filename) = *pp; 256 return *pp; 257 } 258 p = estrndup(new_compiled_filename, length); 259 zend_hash_update(&CG(filenames_table), new_compiled_filename, length+1, &p, sizeof(char *), (void **) &pp); 260 CG(compiled_filename) = p; 261 return p; 262} 263/* }}} */ 264 265ZEND_API void zend_restore_compiled_filename(char *original_compiled_filename TSRMLS_DC) /* {{{ */ 266{ 267 CG(compiled_filename) = original_compiled_filename; 268} 269/* }}} */ 270 271ZEND_API char *zend_get_compiled_filename(TSRMLS_D) /* {{{ */ 272{ 273 return CG(compiled_filename); 274} 275/* }}} */ 276 277ZEND_API int zend_get_compiled_lineno(TSRMLS_D) /* {{{ */ 278{ 279 return CG(zend_lineno); 280} 281/* }}} */ 282 283ZEND_API zend_bool zend_is_compiling(TSRMLS_D) /* {{{ */ 284{ 285 return CG(in_compilation); 286} 287/* }}} */ 288 289static zend_uint get_temporary_variable(zend_op_array *op_array) /* {{{ */ 290{ 291 return (zend_uint)(zend_uintptr_t)EX_TMP_VAR_NUM(0, (op_array->T)++); 292} 293/* }}} */ 294 295static int lookup_cv(zend_op_array *op_array, char* name, int name_len, ulong hash TSRMLS_DC) /* {{{ */ 296{ 297 int i = 0; 298 ulong hash_value = hash ? hash : zend_inline_hash_func(name, name_len+1); 299 300 while (i < op_array->last_var) { 301 if (op_array->vars[i].name == name || 302 (op_array->vars[i].hash_value == hash_value && 303 op_array->vars[i].name_len == name_len && 304 memcmp(op_array->vars[i].name, name, name_len) == 0)) { 305 str_efree(name); 306 return i; 307 } 308 i++; 309 } 310 i = op_array->last_var; 311 op_array->last_var++; 312 if (op_array->last_var > CG(context).vars_size) { 313 CG(context).vars_size += 16; /* FIXME */ 314 op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_compiled_variable)); 315 } 316 op_array->vars[i].name = zend_new_interned_string(name, name_len + 1, 1 TSRMLS_CC); 317 op_array->vars[i].name_len = name_len; 318 op_array->vars[i].hash_value = hash_value; 319 return i; 320} 321/* }}} */ 322 323void zend_del_literal(zend_op_array *op_array, int n) /* {{{ */ 324{ 325 zval_dtor(&CONSTANT_EX(op_array, n)); 326 if (n + 1 == op_array->last_literal) { 327 op_array->last_literal--; 328 } else { 329 Z_TYPE(CONSTANT_EX(op_array, n)) = IS_NULL; 330 } 331} 332/* }}} */ 333 334/* Common part of zend_add_literal and zend_append_individual_literal */ 335static inline void zend_insert_literal(zend_op_array *op_array, const zval *zv, int literal_position TSRMLS_DC) /* {{{ */ 336{ 337 if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) { 338 zval *z = (zval*)zv; 339 Z_STRVAL_P(z) = (char*)zend_new_interned_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv) + 1, 1 TSRMLS_CC); 340 } 341 CONSTANT_EX(op_array, literal_position) = *zv; 342 Z_SET_REFCOUNT(CONSTANT_EX(op_array, literal_position), 2); 343 Z_SET_ISREF(CONSTANT_EX(op_array, literal_position)); 344 op_array->literals[literal_position].hash_value = 0; 345 op_array->literals[literal_position].cache_slot = -1; 346} 347/* }}} */ 348 349/* Is used while compiling a function, using the context to keep track 350 of an approximate size to avoid to relocate to often. 351 Literals are truncated to actual size in the second compiler pass (pass_two()). */ 352int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */ 353{ 354 int i = op_array->last_literal; 355 op_array->last_literal++; 356 if (i >= CG(context).literals_size) { 357 while (i >= CG(context).literals_size) { 358 CG(context).literals_size += 16; /* FIXME */ 359 } 360 op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal)); 361 } 362 zend_insert_literal(op_array, zv, i TSRMLS_CC); 363 return i; 364} 365/* }}} */ 366 367/* Is used after normal compilation to append an additional literal. 368 Allocation is done precisely here. */ 369int zend_append_individual_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */ 370{ 371 int i = op_array->last_literal; 372 op_array->last_literal++; 373 op_array->literals = (zend_literal*)erealloc(op_array->literals, (i + 1) * sizeof(zend_literal)); 374 zend_insert_literal(op_array, zv, i TSRMLS_CC); 375 return i; 376} 377/* }}} */ 378 379int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */ 380{ 381 int ret; 382 char *lc_name; 383 zval c; 384 int lc_literal; 385 386 if (op_array->last_literal > 0 && 387 &op_array->literals[op_array->last_literal - 1].constant == zv && 388 op_array->literals[op_array->last_literal - 1].cache_slot == -1) { 389 /* we already have function name as last literal (do nothing) */ 390 ret = op_array->last_literal - 1; 391 } else { 392 ret = zend_add_literal(op_array, zv TSRMLS_CC); 393 } 394 395 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); 396 ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0); 397 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 398 CALCULATE_LITERAL_HASH(lc_literal); 399 400 return ret; 401} 402/* }}} */ 403 404int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */ 405{ 406 int ret; 407 char *lc_name; 408 const char *ns_separator; 409 int lc_len; 410 zval c; 411 int lc_literal; 412 413 if (op_array->last_literal > 0 && 414 &op_array->literals[op_array->last_literal - 1].constant == zv && 415 op_array->literals[op_array->last_literal - 1].cache_slot == -1) { 416 /* we already have function name as last literal (do nothing) */ 417 ret = op_array->last_literal - 1; 418 } else { 419 ret = zend_add_literal(op_array, zv TSRMLS_CC); 420 } 421 422 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); 423 ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0); 424 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 425 CALCULATE_LITERAL_HASH(lc_literal); 426 427 ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv)) + 1; 428 lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv)); 429 lc_name = zend_str_tolower_dup(ns_separator, lc_len); 430 ZVAL_STRINGL(&c, lc_name, lc_len, 0); 431 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 432 CALCULATE_LITERAL_HASH(lc_literal); 433 434 return ret; 435} 436/* }}} */ 437 438int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */ 439{ 440 int ret; 441 char *lc_name; 442 int lc_len; 443 zval c; 444 int lc_literal; 445 446 if (op_array->last_literal > 0 && 447 &op_array->literals[op_array->last_literal - 1].constant == zv && 448 op_array->literals[op_array->last_literal - 1].cache_slot == -1) { 449 /* we already have function name as last literal (do nothing) */ 450 ret = op_array->last_literal - 1; 451 } else { 452 ret = zend_add_literal(op_array, zv TSRMLS_CC); 453 } 454 455 if (Z_STRVAL_P(zv)[0] == '\\') { 456 lc_len = Z_STRLEN_P(zv) - 1; 457 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv) + 1, lc_len); 458 } else { 459 lc_len = Z_STRLEN_P(zv); 460 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), lc_len); 461 } 462 ZVAL_STRINGL(&c, lc_name, lc_len, 0); 463 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 464 CALCULATE_LITERAL_HASH(lc_literal); 465 466 GET_CACHE_SLOT(ret); 467 468 return ret; 469} 470/* }}} */ 471 472int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unqualified TSRMLS_DC) /* {{{ */ 473{ 474 int ret, tmp_literal; 475 char *name, *tmp_name; 476 const char *ns_separator; 477 int name_len, ns_len; 478 zval c; 479 480 if (op_array->last_literal > 0 && 481 &op_array->literals[op_array->last_literal - 1].constant == zv && 482 op_array->literals[op_array->last_literal - 1].cache_slot == -1) { 483 /* we already have function name as last literal (do nothing) */ 484 ret = op_array->last_literal - 1; 485 } else { 486 ret = zend_add_literal(op_array, zv TSRMLS_CC); 487 } 488 489 /* skip leading '\\' */ 490 if (Z_STRVAL_P(zv)[0] == '\\') { 491 name_len = Z_STRLEN_P(zv) - 1; 492 name = Z_STRVAL_P(zv) + 1; 493 } else { 494 name_len = Z_STRLEN_P(zv); 495 name = Z_STRVAL_P(zv); 496 } 497 ns_separator = zend_memrchr(name, '\\', name_len); 498 if (ns_separator) { 499 ns_len = ns_separator - name; 500 } else { 501 ns_len = 0; 502 } 503 504 if (ns_len) { 505 /* lowercased namespace name & original constant name */ 506 tmp_name = estrndup(name, name_len); 507 zend_str_tolower(tmp_name, ns_len); 508 ZVAL_STRINGL(&c, tmp_name, name_len, 0); 509 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 510 CALCULATE_LITERAL_HASH(tmp_literal); 511 512 /* lowercased namespace name & lowercased constant name */ 513 tmp_name = zend_str_tolower_dup(name, name_len); 514 ZVAL_STRINGL(&c, tmp_name, name_len, 0); 515 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 516 CALCULATE_LITERAL_HASH(tmp_literal); 517 } 518 519 if (ns_len) { 520 if (!unqualified) { 521 return ret; 522 } 523 ns_len++; 524 name += ns_len; 525 name_len -= ns_len; 526 } 527 528 /* original constant name */ 529 tmp_name = estrndup(name, name_len); 530 ZVAL_STRINGL(&c, tmp_name, name_len, 0); 531 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 532 CALCULATE_LITERAL_HASH(tmp_literal); 533 534 /* lowercased constant name */ 535 tmp_name = zend_str_tolower_dup(name, name_len); 536 ZVAL_STRINGL(&c, tmp_name, name_len, 0); 537 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC); 538 CALCULATE_LITERAL_HASH(tmp_literal); 539 540 return ret; 541} 542/* }}} */ 543 544#define LITERAL_STRINGL(op, str, len, copy) do { \ 545 zval _c; \ 546 ZVAL_STRINGL(&_c, str, len, copy); \ 547 op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \ 548 } while (0) 549 550#define LITERAL_LONG(op, val) do { \ 551 zval _c; \ 552 ZVAL_LONG(&_c, val); \ 553 op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \ 554 } while (0) 555 556#define LITERAL_LONG_EX(op_array, op, val) do { \ 557 zval _c; \ 558 ZVAL_LONG(&_c, val); \ 559 op.constant = zend_add_literal(op_array, &_c TSRMLS_CC); \ 560 } while (0) 561 562#define LITERAL_NULL(op) do { \ 563 zval _c; \ 564 INIT_ZVAL( _c); \ 565 op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \ 566 } while (0) 567 568static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */ 569{ 570 zend_uint type = variable->EA; 571 572 return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL)); 573} 574/* }}} */ 575 576void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */ 577{ 578 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 579 580 opline->opcode = op; 581 opline->result_type = IS_TMP_VAR; 582 opline->result.var = get_temporary_variable(CG(active_op_array)); 583 SET_NODE(opline->op1, op1); 584 SET_NODE(opline->op2, op2); 585 GET_NODE(result, opline->result); 586} 587/* }}} */ 588 589void zend_do_unary_op(zend_uchar op, znode *result, const znode *op1 TSRMLS_DC) /* {{{ */ 590{ 591 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 592 593 opline->opcode = op; 594 opline->result_type = IS_TMP_VAR; 595 opline->result.var = get_temporary_variable(CG(active_op_array)); 596 SET_NODE(opline->op1, op1); 597 GET_NODE(result, opline->result); 598 SET_UNUSED(opline->op2); 599} 600/* }}} */ 601 602#define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; } 603 604static void zend_do_op_data(zend_op *data_op, const znode *value TSRMLS_DC) /* {{{ */ 605{ 606 data_op->opcode = ZEND_OP_DATA; 607 SET_NODE(data_op->op1, value); 608 SET_UNUSED(data_op->op2); 609} 610/* }}} */ 611 612void zend_do_binary_assign_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */ 613{ 614 int last_op_number = get_next_op_number(CG(active_op_array)); 615 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 616 617 if (last_op_number > 0) { 618 zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1]; 619 620 switch (last_op->opcode) { 621 case ZEND_FETCH_OBJ_RW: 622 last_op->opcode = op; 623 last_op->extended_value = ZEND_ASSIGN_OBJ; 624 625 zend_do_op_data(opline, op2 TSRMLS_CC); 626 SET_UNUSED(opline->result); 627 GET_NODE(result, last_op->result); 628 return; 629 case ZEND_FETCH_DIM_RW: 630 last_op->opcode = op; 631 last_op->extended_value = ZEND_ASSIGN_DIM; 632 633 zend_do_op_data(opline, op2 TSRMLS_CC); 634 opline->op2.var = get_temporary_variable(CG(active_op_array)); 635 opline->op2_type = IS_VAR; 636 SET_UNUSED(opline->result); 637 GET_NODE(result,last_op->result); 638 return; 639 default: 640 break; 641 } 642 } 643 644 opline->opcode = op; 645 SET_NODE(opline->op1, op1); 646 SET_NODE(opline->op2, op2); 647 opline->result_type = IS_VAR; 648 opline->result.var = get_temporary_variable(CG(active_op_array)); 649 GET_NODE(result, opline->result); 650} 651/* }}} */ 652 653void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC) /* {{{ */ 654{ 655 zend_op opline; 656 zend_op *opline_ptr; 657 zend_llist *fetch_list_ptr; 658 659 if (varname->op_type == IS_CONST) { 660 ulong hash = 0; 661 662 if (Z_TYPE(varname->u.constant) != IS_STRING) { 663 convert_to_string(&varname->u.constant); 664 } else if (IS_INTERNED(Z_STRVAL(varname->u.constant))) { 665 hash = INTERNED_HASH(Z_STRVAL(varname->u.constant)); 666 } 667 if (!zend_is_auto_global_quick(varname->u.constant.value.str.val, varname->u.constant.value.str.len, hash TSRMLS_CC) && 668 !(varname->u.constant.value.str.len == (sizeof("this")-1) && 669 !memcmp(varname->u.constant.value.str.val, "this", sizeof("this"))) && 670 (CG(active_op_array)->last == 0 || 671 CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE)) { 672 result->op_type = IS_CV; 673 result->u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len, hash TSRMLS_CC); 674 varname->u.constant.value.str.val = (char*)CG(active_op_array)->vars[result->u.op.var].name; 675 result->EA = 0; 676 return; 677 } 678 } 679 680 if (bp) { 681 opline_ptr = &opline; 682 init_op(opline_ptr TSRMLS_CC); 683 } else { 684 opline_ptr = get_next_op(CG(active_op_array) TSRMLS_CC); 685 } 686 687 opline_ptr->opcode = op; 688 opline_ptr->result_type = IS_VAR; 689 opline_ptr->result.var = get_temporary_variable(CG(active_op_array)); 690 SET_NODE(opline_ptr->op1, varname); 691 GET_NODE(result, opline_ptr->result); 692 SET_UNUSED(opline_ptr->op2); 693 opline_ptr->extended_value = ZEND_FETCH_LOCAL; 694 695 if (varname->op_type == IS_CONST) { 696 CALCULATE_LITERAL_HASH(opline_ptr->op1.constant); 697 if (zend_is_auto_global_quick(varname->u.constant.value.str.val, varname->u.constant.value.str.len, Z_HASH_P(&CONSTANT(opline_ptr->op1.constant)) TSRMLS_CC)) { 698 opline_ptr->extended_value = ZEND_FETCH_GLOBAL; 699 } 700 } 701 702 if (bp) { 703 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); 704 zend_llist_add_element(fetch_list_ptr, opline_ptr); 705 } 706} 707/* }}} */ 708 709void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC) /* {{{ */ 710{ 711 /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */ 712 fetch_simple_variable_ex(result, varname, bp, ZEND_FETCH_W TSRMLS_CC); 713} 714/* }}} */ 715 716void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */ 717{ 718 znode class_node; 719 zend_llist *fetch_list_ptr; 720 zend_llist_element *le; 721 zend_op *opline_ptr; 722 zend_op opline; 723 724 if (class_name->op_type == IS_CONST && 725 ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { 726 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC); 727 class_node = *class_name; 728 } else { 729 zend_do_fetch_class(&class_node, class_name TSRMLS_CC); 730 } 731 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); 732 if (result->op_type == IS_CV) { 733 init_op(&opline TSRMLS_CC); 734 735 opline.opcode = ZEND_FETCH_W; 736 opline.result_type = IS_VAR; 737 opline.result.var = get_temporary_variable(CG(active_op_array)); 738 opline.op1_type = IS_CONST; 739 LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[result->u.op.var].name), CG(active_op_array)->vars[result->u.op.var].name_len, 0); 740 CALCULATE_LITERAL_HASH(opline.op1.constant); 741 GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant); 742 if (class_node.op_type == IS_CONST) { 743 opline.op2_type = IS_CONST; 744 opline.op2.constant = 745 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); 746 } else { 747 SET_NODE(opline.op2, &class_node); 748 } 749 GET_NODE(result,opline.result); 750 opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; 751 opline_ptr = &opline; 752 753 zend_llist_add_element(fetch_list_ptr, &opline); 754 } else { 755 le = fetch_list_ptr->head; 756 757 opline_ptr = (zend_op *)le->data; 758 if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1_type == IS_CV) { 759 init_op(&opline TSRMLS_CC); 760 opline.opcode = ZEND_FETCH_W; 761 opline.result_type = IS_VAR; 762 opline.result.var = get_temporary_variable(CG(active_op_array)); 763 opline.op1_type = IS_CONST; 764 LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[opline_ptr->op1.var].name), CG(active_op_array)->vars[opline_ptr->op1.var].name_len, 0); 765 CALCULATE_LITERAL_HASH(opline.op1.constant); 766 GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant); 767 if (class_node.op_type == IS_CONST) { 768 opline.op2_type = IS_CONST; 769 opline.op2.constant = 770 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); 771 } else { 772 SET_NODE(opline.op2, &class_node); 773 } 774 opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; 775 COPY_NODE(opline_ptr->op1, opline.result); 776 777 zend_llist_prepend_element(fetch_list_ptr, &opline); 778 } else { 779 if (opline_ptr->op1_type == IS_CONST) { 780 GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op1.constant); 781 } 782 if (class_node.op_type == IS_CONST) { 783 opline_ptr->op2_type = IS_CONST; 784 opline_ptr->op2.constant = 785 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); 786 } else { 787 SET_NODE(opline_ptr->op2, &class_node); 788 } 789 opline_ptr->extended_value |= ZEND_FETCH_STATIC_MEMBER; 790 } 791 } 792} 793/* }}} */ 794 795void fetch_array_begin(znode *result, znode *varname, znode *first_dim TSRMLS_DC) /* {{{ */ 796{ 797 fetch_simple_variable(result, varname, 1 TSRMLS_CC); 798 799 fetch_array_dim(result, result, first_dim TSRMLS_CC); 800} 801/* }}} */ 802 803void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS_DC) /* {{{ */ 804{ 805 zend_op opline; 806 zend_llist *fetch_list_ptr; 807 808 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); 809 810 if (zend_is_function_or_method_call(parent)) { 811 init_op(&opline TSRMLS_CC); 812 opline.opcode = ZEND_SEPARATE; 813 SET_NODE(opline.op1, parent); 814 SET_UNUSED(opline.op2); 815 opline.result_type = IS_VAR; 816 opline.result.var = opline.op1.var; 817 zend_llist_add_element(fetch_list_ptr, &opline); 818 } 819 820 init_op(&opline TSRMLS_CC); 821 opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */ 822 opline.result_type = IS_VAR; 823 opline.result.var = get_temporary_variable(CG(active_op_array)); 824 SET_NODE(opline.op1, parent); 825 SET_NODE(opline.op2, dim); 826 if (opline.op2_type == IS_CONST && Z_TYPE(CONSTANT(opline.op2.constant)) == IS_STRING) { 827 ulong index; 828 int numeric = 0; 829 830 ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1, index, numeric = 1); 831 if (numeric) { 832 zval_dtor(&CONSTANT(opline.op2.constant)); 833 ZVAL_LONG(&CONSTANT(opline.op2.constant), index); 834 } else { 835 CALCULATE_LITERAL_HASH(opline.op2.constant); 836 } 837 } 838 839 GET_NODE(result, opline.result); 840 841 zend_llist_add_element(fetch_list_ptr, &opline); 842} 843/* }}} */ 844 845void fetch_string_offset(znode *result, const znode *parent, const znode *offset TSRMLS_DC) /* {{{ */ 846{ 847 fetch_array_dim(result, parent, offset TSRMLS_CC); 848} 849/* }}} */ 850 851void zend_do_print(znode *result, const znode *arg TSRMLS_DC) /* {{{ */ 852{ 853 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 854 855 opline->result_type = IS_TMP_VAR; 856 opline->result.var = get_temporary_variable(CG(active_op_array)); 857 opline->opcode = ZEND_PRINT; 858 SET_NODE(opline->op1, arg); 859 SET_UNUSED(opline->op2); 860 GET_NODE(result, opline->result); 861} 862/* }}} */ 863 864void zend_do_echo(const znode *arg TSRMLS_DC) /* {{{ */ 865{ 866 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 867 868 opline->opcode = ZEND_ECHO; 869 SET_NODE(opline->op1, arg); 870 SET_UNUSED(opline->op2); 871} 872/* }}} */ 873 874void zend_do_abstract_method(const znode *function_name, znode *modifiers, const znode *body TSRMLS_DC) /* {{{ */ 875{ 876 char *method_type; 877 878 if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) { 879 Z_LVAL(modifiers->u.constant) |= ZEND_ACC_ABSTRACT; 880 method_type = "Interface"; 881 } else { 882 method_type = "Abstract"; 883 } 884 885 if (modifiers->u.constant.value.lval & ZEND_ACC_ABSTRACT) { 886 if(modifiers->u.constant.value.lval & ZEND_ACC_PRIVATE) { 887 zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val); 888 } 889 if (Z_LVAL(body->u.constant) == ZEND_ACC_ABSTRACT) { 890 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 891 892 opline->opcode = ZEND_RAISE_ABSTRACT_ERROR; 893 SET_UNUSED(opline->op1); 894 SET_UNUSED(opline->op2); 895 } else { 896 /* we had code in the function body */ 897 zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val); 898 } 899 } else { 900 if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) { 901 zend_error(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", CG(active_class_entry)->name, function_name->u.constant.value.str.val); 902 } 903 } 904} 905/* }}} */ 906 907static zend_bool opline_is_fetch_this(const zend_op *opline TSRMLS_DC) /* {{{ */ 908{ 909 if ((opline->opcode == ZEND_FETCH_W) && (opline->op1_type == IS_CONST) 910 && (Z_TYPE(CONSTANT(opline->op1.constant)) == IS_STRING) 911 && (Z_HASH_P(&CONSTANT(opline->op1.constant)) == THIS_HASHVAL) 912 && (Z_STRLEN(CONSTANT(opline->op1.constant)) == (sizeof("this")-1)) 913 && !memcmp(Z_STRVAL(CONSTANT(opline->op1.constant)), "this", sizeof("this"))) { 914 return 1; 915 } else { 916 return 0; 917 } 918} 919/* }}} */ 920 921void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {{{ */ 922{ 923 int last_op_number; 924 zend_op *opline; 925 926 if (value->op_type == IS_CV) { 927 zend_llist *fetch_list_ptr; 928 929 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); 930 if (fetch_list_ptr && fetch_list_ptr->head) { 931 opline = (zend_op *)fetch_list_ptr->head->data; 932 933 if (opline->opcode == ZEND_FETCH_DIM_W && 934 opline->op1_type == IS_CV && 935 opline->op1.var == value->u.op.var) { 936 937 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 938 opline->opcode = ZEND_FETCH_R; 939 opline->result_type = IS_VAR; 940 opline->result.var = get_temporary_variable(CG(active_op_array)); 941 opline->op1_type = IS_CONST; 942 LITERAL_STRINGL(opline->op1, 943 CG(active_op_array)->vars[value->u.op.var].name, 944 CG(active_op_array)->vars[value->u.op.var].name_len, 1); 945 CALCULATE_LITERAL_HASH(opline->op1.constant); 946 SET_UNUSED(opline->op2); 947 opline->extended_value = ZEND_FETCH_LOCAL; 948 GET_NODE(value, opline->result); 949 } 950 } 951 } 952 953 zend_do_end_variable_parse(variable, BP_VAR_W, 0 TSRMLS_CC); 954 955 last_op_number = get_next_op_number(CG(active_op_array)); 956 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 957 958 if (variable->op_type == IS_CV) { 959 if (variable->u.op.var == CG(active_op_array)->this_var) { 960 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); 961 } 962 } else if (variable->op_type == IS_VAR) { 963 int n = 0; 964 965 while (last_op_number - n > 0) { 966 zend_op *last_op; 967 968 last_op = &CG(active_op_array)->opcodes[last_op_number-n-1]; 969 970 if (last_op->result_type == IS_VAR && 971 last_op->result.var == variable->u.op.var) { 972 if (last_op->opcode == ZEND_FETCH_OBJ_W) { 973 if (n > 0) { 974 int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline); 975 *opline = *last_op; 976 MAKE_NOP(last_op); 977 /* last_op = opline; */ 978 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 979 /* get_next_op can realloc, we need to move last_op */ 980 last_op = &CG(active_op_array)->opcodes[opline_no]; 981 } 982 last_op->opcode = ZEND_ASSIGN_OBJ; 983 zend_do_op_data(opline, value TSRMLS_CC); 984 SET_UNUSED(opline->result); 985 GET_NODE(result, last_op->result); 986 return; 987 } else if (last_op->opcode == ZEND_FETCH_DIM_W) { 988 if (n > 0) { 989 int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline); 990 *opline = *last_op; 991 MAKE_NOP(last_op); 992 /* last_op = opline; */ 993 /* TBFixed: this can realloc opcodes, leaving last_op pointing wrong */ 994 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 995 /* get_next_op can realloc, we need to move last_op */ 996 last_op = &CG(active_op_array)->opcodes[opline_no]; 997 } 998 last_op->opcode = ZEND_ASSIGN_DIM; 999 zend_do_op_data(opline, value TSRMLS_CC); 1000 opline->op2.var = get_temporary_variable(CG(active_op_array)); 1001 opline->op2_type = IS_VAR; 1002 SET_UNUSED(opline->result); 1003 GET_NODE(result, last_op->result); 1004 return; 1005 } else if (opline_is_fetch_this(last_op TSRMLS_CC)) { 1006 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); 1007 } else { 1008 break; 1009 } 1010 } 1011 n++; 1012 } 1013 } 1014 1015 opline->opcode = ZEND_ASSIGN; 1016 SET_NODE(opline->op1, variable); 1017 SET_NODE(opline->op2, value); 1018 opline->result_type = IS_VAR; 1019 opline->result.var = get_temporary_variable(CG(active_op_array)); 1020 GET_NODE(result, opline->result); 1021} 1022/* }}} */ 1023 1024void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */ 1025{ 1026 zend_op *opline; 1027 1028 if (lvar->op_type == IS_CV) { 1029 if (lvar->u.op.var == CG(active_op_array)->this_var) { 1030 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); 1031 } 1032 } else if (lvar->op_type == IS_VAR) { 1033 int last_op_number = get_next_op_number(CG(active_op_array)); 1034 1035 if (last_op_number > 0) { 1036 opline = &CG(active_op_array)->opcodes[last_op_number-1]; 1037 if (opline_is_fetch_this(opline TSRMLS_CC)) { 1038 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); 1039 } 1040 } 1041 } 1042 1043 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1044 opline->opcode = ZEND_ASSIGN_REF; 1045 if (zend_is_function_or_method_call(rvar)) { 1046 opline->extended_value = ZEND_RETURNS_FUNCTION; 1047 } else if (rvar->EA & ZEND_PARSED_NEW) { 1048 opline->extended_value = ZEND_RETURNS_NEW; 1049 } else { 1050 opline->extended_value = 0; 1051 } 1052 if (result) { 1053 opline->result_type = IS_VAR; 1054 opline->result.var = get_temporary_variable(CG(active_op_array)); 1055 GET_NODE(result, opline->result); 1056 } else { 1057 opline->result_type = IS_UNUSED | EXT_TYPE_UNUSED; 1058 } 1059 SET_NODE(opline->op1, lvar); 1060 SET_NODE(opline->op2, rvar); 1061} 1062/* }}} */ 1063 1064static inline void do_begin_loop(TSRMLS_D) /* {{{ */ 1065{ 1066 zend_brk_cont_element *brk_cont_element; 1067 int parent; 1068 1069 parent = CG(context).current_brk_cont; 1070 CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont; 1071 brk_cont_element = get_next_brk_cont_element(CG(active_op_array)); 1072 brk_cont_element->start = get_next_op_number(CG(active_op_array)); 1073 brk_cont_element->parent = parent; 1074} 1075/* }}} */ 1076 1077static inline void do_end_loop(int cont_addr, int has_loop_var TSRMLS_DC) /* {{{ */ 1078{ 1079 if (!has_loop_var) { 1080 /* The start fileld is used to free temporary variables in case of exceptions. 1081 * We won't try to free something of we don't have loop variable. 1082 */ 1083 CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].start = -1; 1084 } 1085 CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = cont_addr; 1086 CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array)); 1087 CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent; 1088} 1089/* }}} */ 1090 1091void zend_do_while_cond(const znode *expr, znode *close_bracket_token TSRMLS_DC) /* {{{ */ 1092{ 1093 int while_cond_op_number = get_next_op_number(CG(active_op_array)); 1094 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1095 1096 opline->opcode = ZEND_JMPZ; 1097 SET_NODE(opline->op1, expr); 1098 close_bracket_token->u.op.opline_num = while_cond_op_number; 1099 SET_UNUSED(opline->op2); 1100 1101 do_begin_loop(TSRMLS_C); 1102 INC_BPC(CG(active_op_array)); 1103} 1104/* }}} */ 1105 1106void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC) /* {{{ */ 1107{ 1108 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1109 1110 /* add unconditional jump */ 1111 opline->opcode = ZEND_JMP; 1112 opline->op1.opline_num = while_token->u.op.opline_num; 1113 SET_UNUSED(opline->op1); 1114 SET_UNUSED(opline->op2); 1115 1116 /* update while's conditional jmp */ 1117 CG(active_op_array)->opcodes[close_bracket_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); 1118 1119 do_end_loop(while_token->u.op.opline_num, 0 TSRMLS_CC); 1120 1121 DEC_BPC(CG(active_op_array)); 1122} 1123/* }}} */ 1124 1125void zend_do_for_cond(const znode *expr, znode *second_semicolon_token TSRMLS_DC) /* {{{ */ 1126{ 1127 int for_cond_op_number = get_next_op_number(CG(active_op_array)); 1128 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1129 1130 opline->opcode = ZEND_JMPZNZ; 1131 SET_NODE(opline->op1, expr); /* the conditional expression */ 1132 second_semicolon_token->u.op.opline_num = for_cond_op_number; 1133 SET_UNUSED(opline->op2); 1134} 1135/* }}} */ 1136 1137void zend_do_for_before_statement(const znode *cond_start, const znode *second_semicolon_token TSRMLS_DC) /* {{{ */ 1138{ 1139 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1140 1141 opline->opcode = ZEND_JMP; 1142 opline->op1.opline_num = cond_start->u.op.opline_num; 1143 CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); 1144 SET_UNUSED(opline->op1); 1145 SET_UNUSED(opline->op2); 1146 1147 do_begin_loop(TSRMLS_C); 1148 1149 INC_BPC(CG(active_op_array)); 1150} 1151/* }}} */ 1152 1153void zend_do_for_end(const znode *second_semicolon_token TSRMLS_DC) /* {{{ */ 1154{ 1155 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1156 1157 opline->opcode = ZEND_JMP; 1158 opline->op1.opline_num = second_semicolon_token->u.op.opline_num+1; 1159 CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); 1160 SET_UNUSED(opline->op1); 1161 SET_UNUSED(opline->op2); 1162 1163 do_end_loop(second_semicolon_token->u.op.opline_num+1, 0 TSRMLS_CC); 1164 1165 DEC_BPC(CG(active_op_array)); 1166} 1167/* }}} */ 1168 1169void zend_do_pre_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */ 1170{ 1171 int last_op_number = get_next_op_number(CG(active_op_array)); 1172 zend_op *opline; 1173 1174 if (last_op_number > 0) { 1175 zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1]; 1176 1177 if (last_op->opcode == ZEND_FETCH_OBJ_RW) { 1178 last_op->opcode = (op==ZEND_PRE_INC)?ZEND_PRE_INC_OBJ:ZEND_PRE_DEC_OBJ; 1179 last_op->result_type = IS_VAR; 1180 last_op->result.var = get_temporary_variable(CG(active_op_array)); 1181 GET_NODE(result, last_op->result); 1182 return; 1183 } 1184 } 1185 1186 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1187 opline->opcode = op; 1188 SET_NODE(opline->op1, op1); 1189 SET_UNUSED(opline->op2); 1190 opline->result_type = IS_VAR; 1191 opline->result.var = get_temporary_variable(CG(active_op_array)); 1192 GET_NODE(result, opline->result); 1193} 1194/* }}} */ 1195 1196void zend_do_post_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */ 1197{ 1198 int last_op_number = get_next_op_number(CG(active_op_array)); 1199 zend_op *opline; 1200 1201 if (last_op_number > 0) { 1202 zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1]; 1203 1204 if (last_op->opcode == ZEND_FETCH_OBJ_RW) { 1205 last_op->opcode = (op==ZEND_POST_INC)?ZEND_POST_INC_OBJ:ZEND_POST_DEC_OBJ; 1206 last_op->result_type = IS_TMP_VAR; 1207 last_op->result.var = get_temporary_variable(CG(active_op_array)); 1208 GET_NODE(result, last_op->result); 1209 return; 1210 } 1211 } 1212 1213 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1214 opline->opcode = op; 1215 SET_NODE(opline->op1, op1); 1216 SET_UNUSED(opline->op2); 1217 opline->result_type = IS_TMP_VAR; 1218 opline->result.var = get_temporary_variable(CG(active_op_array)); 1219 GET_NODE(result, opline->result); 1220} 1221/* }}} */ 1222 1223void zend_do_if_cond(const znode *cond, znode *closing_bracket_token TSRMLS_DC) /* {{{ */ 1224{ 1225 int if_cond_op_number = get_next_op_number(CG(active_op_array)); 1226 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1227 1228 opline->opcode = ZEND_JMPZ; 1229 SET_NODE(opline->op1, cond); 1230 closing_bracket_token->u.op.opline_num = if_cond_op_number; 1231 SET_UNUSED(opline->op2); 1232 INC_BPC(CG(active_op_array)); 1233} 1234/* }}} */ 1235 1236void zend_do_if_after_statement(const znode *closing_bracket_token, unsigned char initialize TSRMLS_DC) /* {{{ */ 1237{ 1238 int if_end_op_number = get_next_op_number(CG(active_op_array)); 1239 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1240 zend_llist *jmp_list_ptr; 1241 1242 opline->opcode = ZEND_JMP; 1243 /* save for backpatching */ 1244 if (initialize) { 1245 zend_llist jmp_list; 1246 1247 zend_llist_init(&jmp_list, sizeof(int), NULL, 0); 1248 zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist)); 1249 } 1250 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); 1251 zend_llist_add_element(jmp_list_ptr, &if_end_op_number); 1252 1253 CG(active_op_array)->opcodes[closing_bracket_token->u.op.opline_num].op2.opline_num = if_end_op_number+1; 1254 SET_UNUSED(opline->op1); 1255 SET_UNUSED(opline->op2); 1256} 1257/* }}} */ 1258 1259void zend_do_if_end(TSRMLS_D) /* {{{ */ 1260{ 1261 int next_op_number = get_next_op_number(CG(active_op_array)); 1262 zend_llist *jmp_list_ptr; 1263 zend_llist_element *le; 1264 1265 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); 1266 for (le=jmp_list_ptr->head; le; le = le->next) { 1267 CG(active_op_array)->opcodes[*((int *) le->data)].op1.opline_num = next_op_number; 1268 } 1269 zend_llist_destroy(jmp_list_ptr); 1270 zend_stack_del_top(&CG(bp_stack)); 1271 DEC_BPC(CG(active_op_array)); 1272} 1273/* }}} */ 1274 1275void zend_check_writable_variable(const znode *variable) /* {{{ */ 1276{ 1277 zend_uint type = variable->EA; 1278 1279 if (type & ZEND_PARSED_METHOD_CALL) { 1280 zend_error(E_COMPILE_ERROR, "Can't use method return value in write context"); 1281 } 1282 if (type == ZEND_PARSED_FUNCTION_CALL) { 1283 zend_error(E_COMPILE_ERROR, "Can't use function return value in write context"); 1284 } 1285} 1286/* }}} */ 1287 1288void zend_do_begin_variable_parse(TSRMLS_D) /* {{{ */ 1289{ 1290 zend_llist fetch_list; 1291 1292 zend_llist_init(&fetch_list, sizeof(zend_op), NULL, 0); 1293 zend_stack_push(&CG(bp_stack), (void *) &fetch_list, sizeof(zend_llist)); 1294} 1295/* }}} */ 1296 1297void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC) /* {{{ */ 1298{ 1299 zend_llist *fetch_list_ptr; 1300 zend_llist_element *le; 1301 zend_op *opline = NULL; 1302 zend_op *opline_ptr; 1303 zend_uint this_var = -1; 1304 1305 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); 1306 1307 le = fetch_list_ptr->head; 1308 1309 /* TODO: $foo->x->y->z = 1 should fetch "x" and "y" for R or RW, not just W */ 1310 1311 if (le) { 1312 opline_ptr = (zend_op *)le->data; 1313 if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) { 1314 /* convert to FETCH_?(this) into IS_CV */ 1315 if (CG(active_op_array)->last == 0 || 1316 CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE) { 1317 1318 this_var = opline_ptr->result.var; 1319 if (CG(active_op_array)->this_var == -1) { 1320 CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), Z_STRVAL(CONSTANT(opline_ptr->op1.constant)), Z_STRLEN(CONSTANT(opline_ptr->op1.constant)), Z_HASH_P(&CONSTANT(opline_ptr->op1.constant)) TSRMLS_CC); 1321 Z_TYPE(CONSTANT(opline_ptr->op1.constant)) = IS_NULL; 1322 } else { 1323 zend_del_literal(CG(active_op_array), opline_ptr->op1.constant); 1324 } 1325 le = le->next; 1326 if (variable->op_type == IS_VAR && 1327 variable->u.op.var == this_var) { 1328 variable->op_type = IS_CV; 1329 variable->u.op.var = CG(active_op_array)->this_var; 1330 } 1331 } else if (CG(active_op_array)->this_var == -1) { 1332 CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1, THIS_HASHVAL TSRMLS_CC); 1333 } 1334 } 1335 1336 while (le) { 1337 opline_ptr = (zend_op *)le->data; 1338 if (opline_ptr->opcode == ZEND_SEPARATE) { 1339 if (type != BP_VAR_R && type != BP_VAR_IS) { 1340 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1341 memcpy(opline, opline_ptr, sizeof(zend_op)); 1342 } 1343 le = le->next; 1344 continue; 1345 } 1346 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1347 memcpy(opline, opline_ptr, sizeof(zend_op)); 1348 if (opline->op1_type == IS_VAR && 1349 opline->op1.var == this_var) { 1350 opline->op1_type = IS_CV; 1351 opline->op1.var = CG(active_op_array)->this_var; 1352 } 1353 switch (type) { 1354 case BP_VAR_R: 1355 if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) { 1356 zend_error(E_COMPILE_ERROR, "Cannot use [] for reading"); 1357 } 1358 opline->opcode -= 3; 1359 break; 1360 case BP_VAR_W: 1361 break; 1362 case BP_VAR_RW: 1363 opline->opcode += 3; 1364 break; 1365 case BP_VAR_IS: 1366 if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) { 1367 zend_error(E_COMPILE_ERROR, "Cannot use [] for reading"); 1368 } 1369 opline->opcode += 6; /* 3+3 */ 1370 break; 1371 case BP_VAR_FUNC_ARG: 1372 opline->opcode += 9; /* 3+3+3 */ 1373 opline->extended_value |= arg_offset; 1374 break; 1375 case BP_VAR_UNSET: 1376 if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) { 1377 zend_error(E_COMPILE_ERROR, "Cannot use [] for unsetting"); 1378 } 1379 opline->opcode += 12; /* 3+3+3+3 */ 1380 break; 1381 } 1382 le = le->next; 1383 } 1384 if (opline && type == BP_VAR_W && arg_offset) { 1385 opline->extended_value |= ZEND_FETCH_MAKE_REF; 1386 } 1387 } 1388 zend_llist_destroy(fetch_list_ptr); 1389 zend_stack_del_top(&CG(bp_stack)); 1390} 1391/* }}} */ 1392 1393void zend_do_add_string(znode *result, const znode *op1, znode *op2 TSRMLS_DC) /* {{{ */ 1394{ 1395 zend_op *opline; 1396 1397 if (Z_STRLEN(op2->u.constant) > 1) { 1398 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1399 opline->opcode = ZEND_ADD_STRING; 1400 } else if (Z_STRLEN(op2->u.constant) == 1) { 1401 int ch = *Z_STRVAL(op2->u.constant); 1402 1403 /* Free memory and use ZEND_ADD_CHAR in case of 1 character strings */ 1404 efree(Z_STRVAL(op2->u.constant)); 1405 ZVAL_LONG(&op2->u.constant, ch); 1406 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1407 opline->opcode = ZEND_ADD_CHAR; 1408 } else { /* String can be empty after a variable at the end of a heredoc */ 1409 efree(Z_STRVAL(op2->u.constant)); 1410 return; 1411 } 1412 1413 if (op1) { 1414 SET_NODE(opline->op1, op1); 1415 SET_NODE(opline->result, op1); 1416 } else { 1417 SET_UNUSED(opline->op1); 1418 opline->result_type = IS_TMP_VAR; 1419 opline->result.var = get_temporary_variable(CG(active_op_array)); 1420 } 1421 SET_NODE(opline->op2, op2); 1422 GET_NODE(result, opline->result); 1423} 1424/* }}} */ 1425 1426void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */ 1427{ 1428 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1429 1430 opline->opcode = ZEND_ADD_VAR; 1431 1432 if (op1) { 1433 SET_NODE(opline->op1, op1); 1434 SET_NODE(opline->result, op1); 1435 } else { 1436 SET_UNUSED(opline->op1); 1437 opline->result_type = IS_TMP_VAR; 1438 opline->result.var = get_temporary_variable(CG(active_op_array)); 1439 } 1440 SET_NODE(opline->op2, op2); 1441 GET_NODE(result, opline->result); 1442} 1443/* }}} */ 1444 1445void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */ 1446{ 1447 if (op1->op_type==IS_TMP_VAR) { 1448 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1449 1450 opline->opcode = ZEND_FREE; 1451 SET_NODE(opline->op1, op1); 1452 SET_UNUSED(opline->op2); 1453 } else if (op1->op_type==IS_VAR) { 1454 zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; 1455 1456 while (opline->opcode == ZEND_END_SILENCE || opline->opcode == ZEND_EXT_FCALL_END || opline->opcode == ZEND_OP_DATA) { 1457 opline--; 1458 } 1459 if (opline->result_type == IS_VAR 1460 && opline->result.var == op1->u.op.var) { 1461 if (opline->opcode == ZEND_FETCH_R || 1462 opline->opcode == ZEND_FETCH_DIM_R || 1463 opline->opcode == ZEND_FETCH_OBJ_R || 1464 opline->opcode == ZEND_QM_ASSIGN_VAR) { 1465 /* It's very rare and useless case. It's better to use 1466 additional FREE opcode and simplify the FETCH handlers 1467 their selves */ 1468 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1469 opline->opcode = ZEND_FREE; 1470 SET_NODE(opline->op1, op1); 1471 SET_UNUSED(opline->op2); 1472 } else { 1473 opline->result_type |= EXT_TYPE_UNUSED; 1474 } 1475 } else { 1476 while (opline>CG(active_op_array)->opcodes) { 1477 if (opline->opcode == ZEND_FETCH_DIM_R 1478 && opline->op1_type == IS_VAR 1479 && opline->op1.var == op1->u.op.var) { 1480 /* This should the end of a list() construct 1481 * Mark its result as unused 1482 */ 1483 opline->extended_value = ZEND_FETCH_STANDARD; 1484 break; 1485 } else if (opline->result_type==IS_VAR 1486 && opline->result.var == op1->u.op.var) { 1487 if (opline->opcode == ZEND_NEW) { 1488 opline->result_type |= EXT_TYPE_UNUSED; 1489 } 1490 break; 1491 } 1492 opline--; 1493 } 1494 } 1495 } else if (op1->op_type == IS_CONST) { 1496 zval_dtor(&op1->u.constant); 1497 } 1498} 1499/* }}} */ 1500 1501int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier) /* {{{ */ 1502{ 1503 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_PPP_MASK) 1504 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_PPP_MASK)) { 1505 zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed"); 1506 } 1507 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_ABSTRACT) 1508 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_ABSTRACT)) { 1509 zend_error(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed"); 1510 } 1511 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_STATIC) 1512 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_STATIC)) { 1513 zend_error(E_COMPILE_ERROR, "Multiple static modifiers are not allowed"); 1514 } 1515 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_FINAL) 1516 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_FINAL)) { 1517 zend_error(E_COMPILE_ERROR, "Multiple final modifiers are not allowed"); 1518 } 1519 if (((Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant)) & (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) == (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) { 1520 zend_error(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member"); 1521 } 1522 return (Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant)); 1523} 1524/* }}} */ 1525 1526void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */ 1527{ 1528 zend_op_array op_array; 1529 char *name = function_name->u.constant.value.str.val; 1530 int name_len = function_name->u.constant.value.str.len; 1531 int function_begin_line = function_token->u.op.opline_num; 1532 zend_uint fn_flags; 1533 const char *lcname; 1534 zend_bool orig_interactive; 1535 ALLOCA_FLAG(use_heap) 1536 1537 if (is_method) { 1538 if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) { 1539 if ((Z_LVAL(fn_flags_znode->u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC))) { 1540 zend_error(E_COMPILE_ERROR, "Access type for interface method %s::%s() must be omitted", CG(active_class_entry)->name, function_name->u.constant.value.str.val); 1541 } 1542 Z_LVAL(fn_flags_znode->u.constant) |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */ 1543 } 1544 fn_flags = Z_LVAL(fn_flags_znode->u.constant); /* must be done *after* the above check */ 1545 } else { 1546 fn_flags = 0; 1547 } 1548 if ((fn_flags & ZEND_ACC_STATIC) && (fn_flags & ZEND_ACC_ABSTRACT) && !(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) { 1549 zend_error(E_STRICT, "Static function %s%s%s() should not be abstract", is_method ? CG(active_class_entry)->name : "", is_method ? "::" : "", Z_STRVAL(function_name->u.constant)); 1550 } 1551 1552 function_token->u.op_array = CG(active_op_array); 1553 1554 orig_interactive = CG(interactive); 1555 CG(interactive) = 0; 1556 init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); 1557 CG(interactive) = orig_interactive; 1558 1559 op_array.function_name = name; 1560 if (return_reference) { 1561 op_array.fn_flags |= ZEND_ACC_RETURN_REFERENCE; 1562 } 1563 op_array.fn_flags |= fn_flags; 1564 1565 op_array.scope = is_method?CG(active_class_entry):NULL; 1566 op_array.prototype = NULL; 1567 1568 op_array.line_start = zend_get_compiled_lineno(TSRMLS_C); 1569 1570 if (is_method) { 1571 int result; 1572 1573 lcname = zend_new_interned_string(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC); 1574 1575 if (IS_INTERNED(lcname)) { 1576 result = zend_hash_quick_add(&CG(active_class_entry)->function_table, lcname, name_len+1, INTERNED_HASH(lcname), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); 1577 } else { 1578 result = zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); 1579 } 1580 if (result == FAILURE) { 1581 zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name); 1582 } 1583 1584 zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); 1585 zend_init_compiler_context(TSRMLS_C); 1586 1587 if (fn_flags & ZEND_ACC_ABSTRACT) { 1588 CG(active_class_entry)->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; 1589 } 1590 1591 if (!(fn_flags & ZEND_ACC_PPP_MASK)) { 1592 fn_flags |= ZEND_ACC_PUBLIC; 1593 } 1594 1595 if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) { 1596 if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) { 1597 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1598 zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static"); 1599 } 1600 } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) { 1601 if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) { 1602 zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static"); 1603 } 1604 } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) { 1605 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1606 zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static"); 1607 } 1608 } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) { 1609 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1610 zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static"); 1611 } 1612 } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) { 1613 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1614 zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static"); 1615 } 1616 } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) { 1617 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1618 zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static"); 1619 } 1620 } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) { 1621 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1622 zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static"); 1623 } 1624 } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) { 1625 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1626 zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static"); 1627 } 1628 } 1629 } else { 1630 char *class_lcname; 1631 1632 class_lcname = do_alloca(CG(active_class_entry)->name_length + 1, use_heap); 1633 zend_str_tolower_copy(class_lcname, CG(active_class_entry)->name, CG(active_class_entry)->name_length); 1634 /* Improve after RC: cache the lowercase class name */ 1635 1636 if ((CG(active_class_entry)->name_length == name_len) && ((CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) && (!memcmp(class_lcname, lcname, name_len))) { 1637 if (!CG(active_class_entry)->constructor) { 1638 CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array); 1639 } 1640 } else if ((name_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)))) { 1641 if (CG(active_class_entry)->constructor) { 1642 zend_error(E_STRICT, "Redefining already defined constructor for class %s", CG(active_class_entry)->name); 1643 } 1644 CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array); 1645 } else if ((name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1))) { 1646 CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array); 1647 } else if ((name_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1))) { 1648 CG(active_class_entry)->clone = (zend_function *) CG(active_op_array); 1649 } else if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) { 1650 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1651 zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static"); 1652 } 1653 CG(active_class_entry)->__call = (zend_function *) CG(active_op_array); 1654 } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) { 1655 if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) { 1656 zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static"); 1657 } 1658 CG(active_class_entry)->__callstatic = (zend_function *) CG(active_op_array); 1659 } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) { 1660 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1661 zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static"); 1662 } 1663 CG(active_class_entry)->__get = (zend_function *) CG(active_op_array); 1664 } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) { 1665 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1666 zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static"); 1667 } 1668 CG(active_class_entry)->__set = (zend_function *) CG(active_op_array); 1669 } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) { 1670 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1671 zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static"); 1672 } 1673 CG(active_class_entry)->__unset = (zend_function *) CG(active_op_array); 1674 } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) { 1675 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1676 zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static"); 1677 } 1678 CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array); 1679 } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) { 1680 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1681 zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static"); 1682 } 1683 CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array); 1684 } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) { 1685 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { 1686 zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static"); 1687 } 1688 } else if (!(fn_flags & ZEND_ACC_STATIC)) { 1689 CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC; 1690 } 1691 free_alloca(class_lcname, use_heap); 1692 } 1693 1694 str_efree(lcname); 1695 } else { 1696 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1697 zval key; 1698 1699 if (CG(current_namespace)) { 1700 /* Prefix function name with current namespace name */ 1701 znode tmp; 1702 1703 tmp.u.constant = *CG(current_namespace); 1704 zval_copy_ctor(&tmp.u.constant); 1705 zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); 1706 op_array.function_name = Z_STRVAL(tmp.u.constant); 1707 name_len = Z_STRLEN(tmp.u.constant); 1708 lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len); 1709 } else { 1710 lcname = zend_str_tolower_dup(name, name_len); 1711 } 1712 1713 opline->opcode = ZEND_DECLARE_FUNCTION; 1714 opline->op1_type = IS_CONST; 1715 build_runtime_defined_function_key(&key, lcname, name_len TSRMLS_CC); 1716 opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC); 1717 Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))); 1718 opline->op2_type = IS_CONST; 1719 LITERAL_STRINGL(opline->op2, lcname, name_len, 0); 1720 CALCULATE_LITERAL_HASH(opline->op2.constant); 1721 opline->extended_value = ZEND_DECLARE_FUNCTION; 1722 zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); 1723 zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); 1724 zend_init_compiler_context(TSRMLS_C); 1725 } 1726 1727 if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) { 1728 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1729 1730 opline->opcode = ZEND_EXT_NOP; 1731 opline->lineno = function_begin_line; 1732 SET_UNUSED(opline->op1); 1733 SET_UNUSED(opline->op2); 1734 } 1735 1736 { 1737 /* Push a seperator to the switch stack */ 1738 zend_switch_entry switch_entry; 1739 1740 switch_entry.cond.op_type = IS_UNUSED; 1741 switch_entry.default_case = 0; 1742 switch_entry.control_var = 0; 1743 1744 zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry)); 1745 } 1746 1747 { 1748 /* Push a separator to the foreach stack */ 1749 zend_op dummy_opline; 1750 1751 dummy_opline.result_type = IS_UNUSED; 1752 dummy_opline.op1_type = IS_UNUSED; 1753 1754 zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op)); 1755 } 1756 1757 if (CG(doc_comment)) { 1758 CG(active_op_array)->doc_comment = CG(doc_comment); 1759 CG(active_op_array)->doc_comment_len = CG(doc_comment_len); 1760 CG(doc_comment) = NULL; 1761 CG(doc_comment_len) = 0; 1762 } 1763} 1764/* }}} */ 1765 1766void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC) /* {{{ */ 1767{ 1768 znode function_name; 1769 zend_op_array *current_op_array = CG(active_op_array); 1770 int current_op_number = get_next_op_number(CG(active_op_array)); 1771 zend_op *current_op; 1772 1773 function_name.op_type = IS_CONST; 1774 ZVAL_STRINGL(&function_name.u.constant, "{closure}", sizeof("{closure}")-1, 1); 1775 1776 zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC); 1777 1778 result->op_type = IS_TMP_VAR; 1779 result->u.op.var = get_temporary_variable(current_op_array); 1780 1781 current_op = ¤t_op_array->opcodes[current_op_number]; 1782 current_op->opcode = ZEND_DECLARE_LAMBDA_FUNCTION; 1783 zend_del_literal(current_op_array, current_op->op2.constant); 1784 SET_UNUSED(current_op->op2); 1785 SET_NODE(current_op->result, result); 1786 if (is_static) { 1787 CG(active_op_array)->fn_flags |= ZEND_ACC_STATIC; 1788 } 1789 CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE; 1790} 1791/* }}} */ 1792 1793void zend_do_handle_exception(TSRMLS_D) /* {{{ */ 1794{ 1795 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1796 1797 opline->opcode = ZEND_HANDLE_EXCEPTION; 1798 SET_UNUSED(opline->op1); 1799 SET_UNUSED(opline->op2); 1800} 1801/* }}} */ 1802 1803void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /* {{{ */ 1804{ 1805 char lcname[16]; 1806 int name_len; 1807 1808 zend_do_extended_info(TSRMLS_C); 1809 zend_do_return(NULL, 0 TSRMLS_CC); 1810 1811 pass_two(CG(active_op_array) TSRMLS_CC); 1812 zend_release_labels(0 TSRMLS_CC); 1813 1814 if (CG(active_class_entry)) { 1815 zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC); 1816 } else { 1817 /* we don't care if the function name is longer, in fact lowercasing only 1818 * the beginning of the name speeds up the check process */ 1819 name_len = strlen(CG(active_op_array)->function_name); 1820 zend_str_tolower_copy(lcname, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname)-1)); 1821 lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */ 1822 if (name_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)) && CG(active_op_array)->num_args != 1) { 1823 zend_error(E_COMPILE_ERROR, "%s() must take exactly 1 argument", ZEND_AUTOLOAD_FUNC_NAME); 1824 } 1825 } 1826 1827 CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C); 1828 CG(active_op_array) = function_token->u.op_array; 1829 1830 1831 /* Pop the switch and foreach seperators */ 1832 zend_stack_del_top(&CG(switch_cond_stack)); 1833 zend_stack_del_top(&CG(foreach_copy_stack)); 1834} 1835/* }}} */ 1836 1837void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */ 1838{ 1839 zend_op *opline; 1840 zend_arg_info *cur_arg_info; 1841 znode var; 1842 1843 if (class_type->op_type == IS_CONST && 1844 Z_TYPE(class_type->u.constant) == IS_STRING && 1845 Z_STRLEN(class_type->u.constant) == 0) { 1846 /* Usage of namespace as class name not in namespace */ 1847 zval_dtor(&class_type->u.constant); 1848 zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name"); 1849 return; 1850 } 1851 1852 if (zend_is_auto_global_quick(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), 0 TSRMLS_CC)) { 1853 zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant)); 1854 } else { 1855 var.op_type = IS_CV; 1856 var.u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len, 0 TSRMLS_CC); 1857 Z_STRVAL(varname->u.constant) = (char*)CG(active_op_array)->vars[var.u.op.var].name; 1858 var.EA = 0; 1859 if (CG(active_op_array)->vars[var.u.op.var].hash_value == THIS_HASHVAL && 1860 Z_STRLEN(varname->u.constant) == sizeof("this")-1 && 1861 !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) { 1862 if (CG(active_op_array)->scope && 1863 (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) { 1864 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); 1865 } 1866 CG(active_op_array)->this_var = var.u.op.var; 1867 } 1868 } 1869 1870 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 1871 CG(active_op_array)->num_args++; 1872 opline->opcode = op; 1873 SET_NODE(opline->result, &var); 1874 SET_NODE(opline->op1, offset); 1875 if (op == ZEND_RECV_INIT) { 1876 SET_NODE(opline->op2, initialization); 1877 } else { 1878 CG(active_op_array)->required_num_args = CG(active_op_array)->num_args; 1879 SET_UNUSED(opline->op2); 1880 } 1881 CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args)); 1882 cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1]; 1883 cur_arg_info->name = zend_new_interned_string(estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len), varname->u.constant.value.str.len + 1, 1 TSRMLS_CC); 1884 cur_arg_info->name_len = varname->u.constant.value.str.len; 1885 cur_arg_info->type_hint = 0; 1886 cur_arg_info->allow_null = 1; 1887 cur_arg_info->pass_by_reference = pass_by_reference; 1888 cur_arg_info->class_name = NULL; 1889 cur_arg_info->class_name_len = 0; 1890 1891 if (class_type->op_type != IS_UNUSED) { 1892 cur_arg_info->allow_null = 0; 1893 1894 if (class_type->u.constant.type != IS_NULL) { 1895 if (class_type->u.constant.type == IS_ARRAY) { 1896 cur_arg_info->type_hint = IS_ARRAY; 1897 if (op == ZEND_RECV_INIT) { 1898 if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { 1899 cur_arg_info->allow_null = 1; 1900 } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY && Z_TYPE(initialization->u.constant) != IS_CONSTANT_ARRAY) { 1901 zend_error(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL"); 1902 } 1903 } 1904 } else if (class_type->u.constant.type == IS_CALLABLE) { 1905 cur_arg_info->type_hint = IS_CALLABLE; 1906 if (op == ZEND_RECV_INIT) { 1907 if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { 1908 cur_arg_info->allow_null = 1; 1909 } else { 1910 zend_error(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL"); 1911 } 1912 } 1913 } else { 1914 cur_arg_info->type_hint = IS_OBJECT; 1915 if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant), Z_STRLEN(class_type->u.constant))) { 1916 zend_resolve_class_name(class_type, opline->extended_value, 1 TSRMLS_CC); 1917 } 1918 Z_STRVAL(class_type->u.constant) = (char*)zend_new_interned_string(class_type->u.constant.value.str.val, class_type->u.constant.value.str.len + 1, 1 TSRMLS_CC); 1919 cur_arg_info->class_name = class_type->u.constant.value.str.val; 1920 cur_arg_info->class_name_len = class_type->u.constant.value.str.len; 1921 if (op == ZEND_RECV_INIT) { 1922 if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { 1923 cur_arg_info->allow_null = 1; 1924 } else { 1925 zend_error(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL"); 1926 } 1927 } 1928 } 1929 } 1930 } 1931} 1932/* }}} */ 1933 1934int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ 1935{ 1936 zend_function *function; 1937 char *lcname; 1938 char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant)); 1939 1940 zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC); 1941 1942 if (check_namespace && CG(current_namespace) && !is_compound) { 1943 /* We assume we call function from the current namespace 1944 if it is not prefixed. */ 1945 1946 /* In run-time PHP will check for function with full name and 1947 internal function with short name */ 1948 zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC); 1949 return 1; 1950 } 1951 1952 lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); 1953 if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) || 1954 ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) && 1955 (function->type == ZEND_INTERNAL_FUNCTION))) { 1956 zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC); 1957 efree(lcname); 1958 return 1; /* Dynamic */ 1959 } 1960 efree(function_name->u.constant.value.str.val); 1961 function_name->u.constant.value.str.val = lcname; 1962 1963 zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *)); 1964 if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { 1965 CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; 1966 } 1967 zend_do_extended_fcall_begin(TSRMLS_C); 1968 return 0; 1969} 1970/* }}} */ 1971 1972void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ 1973{ 1974 zend_op *last_op; 1975 int last_op_number; 1976 unsigned char *ptr = NULL; 1977 1978 zend_do_end_variable_parse(left_bracket, BP_VAR_R, 0 TSRMLS_CC); 1979 zend_do_begin_variable_parse(TSRMLS_C); 1980 1981 last_op_number = get_next_op_number(CG(active_op_array))-1; 1982 last_op = &CG(active_op_array)->opcodes[last_op_number]; 1983 1984 if ((last_op->op2_type == IS_CONST) && (Z_TYPE(CONSTANT(last_op->op2.constant)) == IS_STRING) && (Z_STRLEN(CONSTANT(last_op->op2.constant)) == sizeof(ZEND_CLONE_FUNC_NAME)-1) 1985 && !zend_binary_strcasecmp(Z_STRVAL(CONSTANT(last_op->op2.constant)), Z_STRLEN(CONSTANT(last_op->op2.constant)), ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1)) { 1986 zend_error(E_COMPILE_ERROR, "Cannot call __clone() method on objects - use 'clone $obj' instead"); 1987 } 1988 1989 if (last_op->opcode == ZEND_FETCH_OBJ_R) { 1990 if (last_op->op2_type == IS_CONST) { 1991 zval name; 1992 name = CONSTANT(last_op->op2.constant); 1993 if (Z_TYPE(name) != IS_STRING) { 1994 zend_error(E_COMPILE_ERROR, "Method name must be a string"); 1995 } 1996 if (!IS_INTERNED(Z_STRVAL(name))) { 1997 Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name)); 1998 } 1999 FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant); 2000 last_op->op2.constant = 2001 zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC); 2002 GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant); 2003 } 2004 last_op->opcode = ZEND_INIT_METHOD_CALL; 2005 last_op->result_type = IS_UNUSED; 2006 last_op->result.num = CG(context).nested_calls; 2007 Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME; 2008 } else { 2009 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2010 opline->opcode = ZEND_INIT_FCALL_BY_NAME; 2011 opline->result.num = CG(context).nested_calls; 2012 SET_UNUSED(opline->op1); 2013 if (left_bracket->op_type == IS_CONST) { 2014 opline->op2_type = IS_CONST; 2015 opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &left_bracket->u.constant TSRMLS_CC); 2016 GET_CACHE_SLOT(opline->op2.constant); 2017 } else { 2018 SET_NODE(opline->op2, left_bracket); 2019 } 2020 } 2021 2022 zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); 2023 if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { 2024 CG(active_op_array)->nested_calls = CG(context).nested_calls; 2025 } 2026 zend_do_extended_fcall_begin(TSRMLS_C); 2027} 2028/* }}} */ 2029 2030void zend_do_clone(znode *result, const znode *expr TSRMLS_DC) /* {{{ */ 2031{ 2032 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2033 2034 opline->opcode = ZEND_CLONE; 2035 SET_NODE(opline->op1, expr); 2036 SET_UNUSED(opline->op2); 2037 opline->result_type = IS_VAR; 2038 opline->result.var = get_temporary_variable(CG(active_op_array)); 2039 GET_NODE(result, opline->result); 2040} 2041/* }}} */ 2042 2043void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */ 2044{ 2045 unsigned char *ptr = NULL; 2046 zend_op *opline; 2047 2048 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2049 if (ns_call) { 2050 /* In run-time PHP will check for function with full name and 2051 internal function with short name */ 2052 opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; 2053 opline->result.num = CG(context).nested_calls; 2054 SET_UNUSED(opline->op1); 2055 opline->op2_type = IS_CONST; 2056 opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); 2057 GET_CACHE_SLOT(opline->op2.constant); 2058 } else { 2059 opline->opcode = ZEND_INIT_FCALL_BY_NAME; 2060 opline->result.num = CG(context).nested_calls; 2061 SET_UNUSED(opline->op1); 2062 if (function_name->op_type == IS_CONST) { 2063 opline->op2_type = IS_CONST; 2064 opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); 2065 GET_CACHE_SLOT(opline->op2.constant); 2066 } else { 2067 SET_NODE(opline->op2, function_name); 2068 } 2069 } 2070 2071 zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); 2072 if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { 2073 CG(active_op_array)->nested_calls = CG(context).nested_calls; 2074 } 2075 zend_do_extended_fcall_begin(TSRMLS_C); 2076} 2077/* }}} */ 2078 2079void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ 2080{ 2081 znode tmp; 2082 int len; 2083 zval **ns; 2084 char *lcname, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant)); 2085 2086 if (Z_STRVAL(element_name->u.constant)[0] == '\\') { 2087 /* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */ 2088 memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+1, Z_STRLEN(element_name->u.constant)); 2089 --Z_STRLEN(element_name->u.constant); 2090 return; 2091 } 2092 2093 if(!check_namespace) { 2094 return; 2095 } 2096 2097 if (compound && CG(current_import)) { 2098 len = compound - Z_STRVAL(element_name->u.constant); 2099 lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); 2100 /* Check if first part of compound name is an import name */ 2101 if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) { 2102 /* Substitute import name */ 2103 tmp.op_type = IS_CONST; 2104 tmp.u.constant = **ns; 2105 zval_copy_ctor(&tmp.u.constant); 2106 len += 1; 2107 Z_STRLEN(element_name->u.constant) -= len; 2108 memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+len, Z_STRLEN(element_name->u.constant)+1); 2109 zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC); 2110 *element_name = tmp; 2111 efree(lcname); 2112 return; 2113 } 2114 efree(lcname); 2115 } 2116 2117 if (CG(current_namespace)) { 2118 tmp = *element_name; 2119 Z_STRLEN(tmp.u.constant) = sizeof("\\")-1 + Z_STRLEN(element_name->u.constant) + Z_STRLEN_P(CG(current_namespace)); 2120 Z_STRVAL(tmp.u.constant) = (char *) emalloc(Z_STRLEN(tmp.u.constant)+1); 2121 memcpy(Z_STRVAL(tmp.u.constant), Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); 2122 memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace))]), "\\", sizeof("\\")-1); 2123 memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace)) + sizeof("\\")-1]), Z_STRVAL(element_name->u.constant), Z_STRLEN(element_name->u.constant)+1); 2124 STR_FREE(Z_STRVAL(element_name->u.constant)); 2125 *element_name = tmp; 2126 } 2127} 2128/* }}} */ 2129 2130void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC) /* {{{ */ 2131{ 2132 char *lcname; 2133 int lctype; 2134 znode constant_name; 2135 2136 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), class_name->u.constant.value.str.len); 2137 lctype = zend_get_class_fetch_type(lcname, strlen(lcname)); 2138 switch (lctype) { 2139 case ZEND_FETCH_CLASS_SELF: 2140 if (!CG(active_class_entry)) { 2141 zend_error(E_COMPILE_ERROR, "Cannot access self::class when no class scope is active"); 2142 } 2143 zval_dtor(&class_name->u.constant); 2144 class_name->op_type = IS_CONST; 2145 ZVAL_STRINGL(&class_name->u.constant, CG(active_class_entry)->name, CG(active_class_entry)->name_length, 1); 2146 *result = *class_name; 2147 break; 2148 case ZEND_FETCH_CLASS_STATIC: 2149 case ZEND_FETCH_CLASS_PARENT: 2150 if (is_static) { 2151 zend_error(E_COMPILE_ERROR, 2152 "%s::class cannot be used for compile-time class name resolution", 2153 lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent" 2154 ); 2155 } 2156 if (!CG(active_class_entry)) { 2157 zend_error(E_COMPILE_ERROR, 2158 "Cannot access %s::class when no class scope is active", 2159 lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent" 2160 ); 2161 } 2162 constant_name.op_type = IS_CONST; 2163 ZVAL_STRINGL(&constant_name.u.constant, "class", sizeof("class")-1, 1); 2164 zend_do_fetch_constant(result, class_name, &constant_name, ZEND_RT, 1 TSRMLS_CC); 2165 break; 2166 case ZEND_FETCH_CLASS_DEFAULT: 2167 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC); 2168 *result = *class_name; 2169 break; 2170 } 2171 2172 efree(lcname); 2173 2174} 2175/* }}} */ 2176 2177void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC) /* {{{ */ 2178{ 2179 char *compound; 2180 char *lcname; 2181 zval **ns; 2182 znode tmp; 2183 int len; 2184 2185 compound = memchr(Z_STRVAL(class_name->u.constant), '\\', Z_STRLEN(class_name->u.constant)); 2186 if (compound) { 2187 /* This is a compound class name that contains namespace prefix */ 2188 if (Z_STRVAL(class_name->u.constant)[0] == '\\') { 2189 /* The STRING name has "\" prefix */ 2190 Z_STRLEN(class_name->u.constant) -= 1; 2191 memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+1, Z_STRLEN(class_name->u.constant)+1); 2192 Z_STRVAL(class_name->u.constant) = erealloc( 2193 Z_STRVAL(class_name->u.constant), 2194 Z_STRLEN(class_name->u.constant) + 1); 2195 2196 if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { 2197 zend_error(E_COMPILE_ERROR, "'\\%s' is an invalid class name", Z_STRVAL(class_name->u.constant)); 2198 } 2199 } else { 2200 if (CG(current_import)) { 2201 len = compound - Z_STRVAL(class_name->u.constant); 2202 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len); 2203 /* Check if first part of compound name is an import name */ 2204 if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) { 2205 /* Substitute import name */ 2206 tmp.op_type = IS_CONST; 2207 tmp.u.constant = **ns; 2208 zval_copy_ctor(&tmp.u.constant); 2209 len += 1; 2210 Z_STRLEN(class_name->u.constant) -= len; 2211 memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1); 2212 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); 2213 *class_name = tmp; 2214 efree(lcname); 2215 return; 2216 } 2217 efree(lcname); 2218 } 2219 /* Here name is not prefixed with \ and not imported */ 2220 if (CG(current_namespace)) { 2221 tmp.op_type = IS_CONST; 2222 tmp.u.constant = *CG(current_namespace); 2223 zval_copy_ctor(&tmp.u.constant); 2224 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); 2225 *class_name = tmp; 2226 } 2227 } 2228 } else if (CG(current_import) || CG(current_namespace)) { 2229 /* this is a plain name (without \) */ 2230 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); 2231 2232 if (CG(current_import) && 2233 zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns) == SUCCESS) { 2234 /* The given name is an import name. Substitute it. */ 2235 zval_dtor(&class_name->u.constant); 2236 class_name->u.constant = **ns; 2237 zval_copy_ctor(&class_name->u.constant); 2238 } else if (CG(current_namespace)) { 2239 /* plain name, no import - prepend current namespace to it */ 2240 tmp.op_type = IS_CONST; 2241 tmp.u.constant = *CG(current_namespace); 2242 zval_copy_ctor(&tmp.u.constant); 2243 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); 2244 *class_name = tmp; 2245 } 2246 efree(lcname); 2247 } 2248} 2249/* }}} */ 2250 2251void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */ 2252{ 2253 long fetch_class_op_number; 2254 zend_op *opline; 2255 2256 if (class_name->op_type == IS_CONST && 2257 Z_TYPE(class_name->u.constant) == IS_STRING && 2258 Z_STRLEN(class_name->u.constant) == 0) { 2259 /* Usage of namespace as class name not in namespace */ 2260 zval_dtor(&class_name->u.constant); 2261 zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name"); 2262 return; 2263 } 2264 2265 fetch_class_op_number = get_next_op_number(CG(active_op_array)); 2266 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2267 2268 opline->opcode = ZEND_FETCH_CLASS; 2269 SET_UNUSED(opline->op1); 2270 opline->extended_value = ZEND_FETCH_CLASS_GLOBAL; 2271 CG(catch_begin) = fetch_class_op_number; 2272 if (class_name->op_type == IS_CONST) { 2273 int fetch_type; 2274 2275 fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); 2276 switch (fetch_type) { 2277 case ZEND_FETCH_CLASS_SELF: 2278 case ZEND_FETCH_CLASS_PARENT: 2279 case ZEND_FETCH_CLASS_STATIC: 2280 SET_UNUSED(opline->op2); 2281 opline->extended_value = fetch_type; 2282 zval_dtor(&class_name->u.constant); 2283 break; 2284 default: 2285 zend_resolve_class_name(class_name, opline->extended_value, 0 TSRMLS_CC); 2286 opline->op2_type = IS_CONST; 2287 opline->op2.constant = 2288 zend_add_class_name_literal(CG(active_op_array), &class_name->u.constant TSRMLS_CC); 2289 break; 2290 } 2291 } else { 2292 SET_NODE(opline->op2, class_name); 2293 } 2294 opline->result.var = get_temporary_variable(CG(active_op_array)); 2295 opline->result_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */ 2296 GET_NODE(result, opline->result); 2297 result->EA = opline->extended_value; 2298} 2299/* }}} */ 2300 2301void zend_do_label(znode *label TSRMLS_DC) /* {{{ */ 2302{ 2303 zend_label dest; 2304 2305 if (!CG(context).labels) { 2306 ALLOC_HASHTABLE(CG(context).labels); 2307 zend_hash_init(CG(context).labels, 4, NULL, NULL, 0); 2308 } 2309 2310 dest.brk_cont = CG(context).current_brk_cont; 2311 dest.opline_num = get_next_op_number(CG(active_op_array)); 2312 2313 if (zend_hash_add(CG(context).labels, Z_STRVAL(label->u.constant), Z_STRLEN(label->u.constant) + 1, (void**)&dest, sizeof(zend_label), NULL) == FAILURE) { 2314 zend_error(E_COMPILE_ERROR, "Label '%s' already defined", Z_STRVAL(label->u.constant)); 2315 } 2316 2317 /* Done with label now */ 2318 zval_dtor(&label->u.constant); 2319} 2320/* }}} */ 2321 2322void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC) /* {{{ */ 2323{ 2324 zend_label *dest; 2325 long current, distance; 2326 zval *label; 2327 2328 if (pass2) { 2329 label = opline->op2.zv; 2330 } else { 2331 label = &CONSTANT_EX(op_array, opline->op2.constant); 2332 } 2333 if (CG(context).labels == NULL || 2334 zend_hash_find(CG(context).labels, Z_STRVAL_P(label), Z_STRLEN_P(label)+1, (void**)&dest) == FAILURE) { 2335 2336 if (pass2) { 2337 CG(in_compilation) = 1; 2338 CG(active_op_array) = op_array; 2339 CG(zend_lineno) = opline->lineno; 2340 zend_error(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label)); 2341 } else { 2342 /* Label is not defined. Delay to pass 2. */ 2343 INC_BPC(op_array); 2344 return; 2345 } 2346 } 2347 2348 opline->op1.opline_num = dest->opline_num; 2349 zval_dtor(label); 2350 Z_TYPE_P(label) = IS_NULL; 2351 2352 /* Check that we are not moving into loop or switch */ 2353 current = opline->extended_value; 2354 for (distance = 0; current != dest->brk_cont; distance++) { 2355 if (current == -1) { 2356 if (pass2) { 2357 CG(in_compilation) = 1; 2358 CG(active_op_array) = op_array; 2359 CG(zend_lineno) = opline->lineno; 2360 } 2361 zend_error(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed"); 2362 } 2363 current = op_array->brk_cont_array[current].parent; 2364 } 2365 2366 if (distance == 0) { 2367 /* Nothing to break out of, optimize to ZEND_JMP */ 2368 opline->opcode = ZEND_JMP; 2369 opline->extended_value = 0; 2370 SET_UNUSED(opline->op2); 2371 } else { 2372 /* Set real break distance */ 2373 ZVAL_LONG(label, distance); 2374 } 2375 2376 if (pass2) { 2377 DEC_BPC(op_array); 2378 } 2379} 2380/* }}} */ 2381 2382void zend_do_goto(const znode *label TSRMLS_DC) /* {{{ */ 2383{ 2384 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2385 2386 opline->opcode = ZEND_GOTO; 2387 opline->extended_value = CG(context).current_brk_cont; 2388 SET_UNUSED(opline->op1); 2389 SET_NODE(opline->op2, label); 2390 zend_resolve_goto_label(CG(active_op_array), opline, 0 TSRMLS_CC); 2391} 2392/* }}} */ 2393 2394void zend_release_labels(int temporary TSRMLS_DC) /* {{{ */ 2395{ 2396 if (CG(context).labels) { 2397 zend_hash_destroy(CG(context).labels); 2398 FREE_HASHTABLE(CG(context).labels); 2399 CG(context).labels = NULL; 2400 } 2401 if (!temporary && !zend_stack_is_empty(&CG(context_stack))) { 2402 zend_compiler_context *ctx; 2403 2404 zend_stack_top(&CG(context_stack), (void**)&ctx); 2405 CG(context) = *ctx; 2406 zend_stack_del_top(&CG(context_stack)); 2407 } 2408} 2409/* }}} */ 2410 2411void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC) /* {{{ */ 2412{ 2413 zend_uint length; 2414 2415 if (!result) { 2416 result = prefix; 2417 } else { 2418 *result = *prefix; 2419 } 2420 2421 if (is_class_member) { 2422 length = sizeof("::")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len; 2423 result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); 2424 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1); 2425 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1); 2426 STR_FREE(name->u.constant.value.str.val); 2427 result->u.constant.value.str.len = length; 2428 } else { 2429 length = sizeof("\\")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len; 2430 result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); 2431 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "\\", sizeof("\\")-1); 2432 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("\\")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1); 2433 STR_FREE(name->u.constant.value.str.val); 2434 result->u.constant.value.str.len = length; 2435 } 2436} 2437/* }}} */ 2438 2439int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */ 2440{ 2441 znode class_node; 2442 unsigned char *ptr = NULL; 2443 zend_op *opline; 2444 2445 if (method_name->op_type == IS_CONST) { 2446 char *lcname; 2447 if (Z_TYPE(method_name->u.constant) != IS_STRING) { 2448 zend_error(E_COMPILE_ERROR, "Method name must be a string"); 2449 } 2450 lcname = zend_str_tolower_dup(Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant)); 2451 if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(method_name->u.constant) && 2452 memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == 0) { 2453 zval_dtor(&method_name->u.constant); 2454 method_name->op_type = IS_UNUSED; 2455 } 2456 efree(lcname); 2457 } 2458 2459 if (class_name->op_type == IS_CONST && 2460 ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { 2461 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC); 2462 class_node = *class_name; 2463 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2464 } else { 2465 zend_do_fetch_class(&class_node, class_name TSRMLS_CC); 2466 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2467 opline->extended_value = class_node.EA ; 2468 } 2469 opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; 2470 opline->result.num = CG(context).nested_calls; 2471 if (class_node.op_type == IS_CONST) { 2472 opline->op1_type = IS_CONST; 2473 opline->op1.constant = 2474 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); 2475 } else { 2476 SET_NODE(opline->op1, &class_node); 2477 } 2478 if (method_name->op_type == IS_CONST) { 2479 opline->op2_type = IS_CONST; 2480 opline->op2.constant = 2481 zend_add_func_name_literal(CG(active_op_array), &method_name->u.constant TSRMLS_CC); 2482 if (opline->op1_type == IS_CONST) { 2483 GET_CACHE_SLOT(opline->op2.constant); 2484 } else { 2485 GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant); 2486 } 2487 } else { 2488 SET_NODE(opline->op2, method_name); 2489 } 2490 2491 zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); 2492 if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { 2493 CG(active_op_array)->nested_calls = CG(context).nested_calls; 2494 } 2495 zend_do_extended_fcall_begin(TSRMLS_C); 2496 return 1; /* Dynamic */ 2497} 2498/* }}} */ 2499 2500void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */ 2501{ 2502 zend_op *opline; 2503 2504 if (is_method && function_name && function_name->op_type == IS_UNUSED) { 2505 /* clone */ 2506 if (Z_LVAL(argument_list->u.constant) != 0) { 2507 zend_error(E_WARNING, "Clone method does not require arguments"); 2508 } 2509 opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; 2510 } else { 2511 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2512 if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { 2513 opline->opcode = ZEND_DO_FCALL; 2514 SET_NODE(opline->op1, function_name); 2515 SET_UNUSED(opline->op2); 2516 opline->op2.num = CG(context).nested_calls; 2517 CALCULATE_LITERAL_HASH(opline->op1.constant); 2518 GET_CACHE_SLOT(opline->op1.constant); 2519 } else { 2520 opline->opcode = ZEND_DO_FCALL_BY_NAME; 2521 SET_UNUSED(opline->op1); 2522 SET_UNUSED(opline->op2); 2523 opline->op2.num = --CG(context).nested_calls; 2524 } 2525 } 2526 2527 opline->result.var = get_temporary_variable(CG(active_op_array)); 2528 opline->result_type = IS_VAR; 2529 GET_NODE(result, opline->result); 2530 2531 zend_stack_del_top(&CG(function_call_stack)); 2532 opline->extended_value = Z_LVAL(argument_list->u.constant); 2533 2534 if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) { 2535 CG(active_op_array)->used_stack = CG(context).used_stack + 1; 2536 } 2537 CG(context).used_stack -= Z_LVAL(argument_list->u.constant); 2538} 2539/* }}} */ 2540 2541void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */ 2542{ 2543 zend_op *opline; 2544 int original_op=op; 2545 zend_function **function_ptr_ptr, *function_ptr; 2546 int send_by_reference; 2547 int send_function = 0; 2548 2549 zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); 2550 function_ptr = *function_ptr_ptr; 2551 2552 if (original_op == ZEND_SEND_REF) { 2553 if (function_ptr && 2554 function_ptr->common.function_name && 2555 function_ptr->common.type == ZEND_USER_FUNCTION && 2556 !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { 2557 zend_error(E_COMPILE_ERROR, 2558 "Call-time pass-by-reference has been removed; " 2559 "If you would like to pass argument by reference, modify the declaration of %s().", 2560 function_ptr->common.function_name); 2561 } else { 2562 zend_error(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed"); 2563 } 2564 return; 2565 } 2566 2567 if (function_ptr) { 2568 if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { 2569 if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) { 2570 send_by_reference = 1; 2571 if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { 2572 /* Method call */ 2573 op = ZEND_SEND_VAR_NO_REF; 2574 send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT; 2575 } 2576 } else { 2577 op = ZEND_SEND_VAL; 2578 send_by_reference = 0; 2579 } 2580 } else { 2581 send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0; 2582 } 2583 } else { 2584 send_by_reference = 0; 2585 } 2586 2587 if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { 2588 /* Method call */ 2589 op = ZEND_SEND_VAR_NO_REF; 2590 send_function = ZEND_ARG_SEND_FUNCTION; 2591 } else if (op == ZEND_SEND_VAL && (param->op_type & (IS_VAR|IS_CV))) { 2592 op = ZEND_SEND_VAR_NO_REF; 2593 } 2594 2595 if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference==ZEND_ARG_SEND_BY_REF) { 2596 /* change to passing by reference */ 2597 switch (param->op_type) { 2598 case IS_VAR: 2599 case IS_CV: 2600 op = ZEND_SEND_REF; 2601 break; 2602 default: 2603 zend_error(E_COMPILE_ERROR, "Only variables can be passed by reference"); 2604 break; 2605 } 2606 } 2607 2608 if (original_op == ZEND_SEND_VAR) { 2609 switch (op) { 2610 case ZEND_SEND_VAR_NO_REF: 2611 zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC); 2612 break; 2613 case ZEND_SEND_VAR: 2614 if (function_ptr) { 2615 zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC); 2616 } else { 2617 zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, offset TSRMLS_CC); 2618 } 2619 break; 2620 case ZEND_SEND_REF: 2621 zend_do_end_variable_parse(param, BP_VAR_W, 0 TSRMLS_CC); 2622 break; 2623 } 2624 } 2625 2626 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2627 2628 if (op == ZEND_SEND_VAR_NO_REF) { 2629 if (function_ptr) { 2630 opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference | send_function; 2631 } else { 2632 opline->extended_value = send_function; 2633 } 2634 } else { 2635 if (function_ptr) { 2636 opline->extended_value = ZEND_DO_FCALL; 2637 } else { 2638 opline->extended_value = ZEND_DO_FCALL_BY_NAME; 2639 } 2640 } 2641 opline->opcode = op; 2642 SET_NODE(opline->op1, param); 2643 opline->op2.opline_num = offset; 2644 SET_UNUSED(opline->op2); 2645 2646 if (++CG(context).used_stack > CG(active_op_array)->used_stack) { 2647 CG(active_op_array)->used_stack = CG(context).used_stack; 2648 } 2649} 2650/* }}} */ 2651 2652static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRMLS_DC) /* {{{ */ 2653{ 2654 zend_op *opline; 2655 2656 if (switch_entry->cond.op_type != IS_VAR && switch_entry->cond.op_type != IS_TMP_VAR) { 2657 return (switch_entry->cond.op_type == IS_UNUSED); 2658 } 2659 2660 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2661 2662 opline->opcode = (switch_entry->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; 2663 SET_NODE(opline->op1, &switch_entry->cond); 2664 SET_UNUSED(opline->op2); 2665 opline->extended_value = 0; 2666 return 0; 2667} 2668/* }}} */ 2669 2670static int generate_free_foreach_copy(const zend_op *foreach_copy TSRMLS_DC) /* {{{ */ 2671{ 2672 zend_op *opline; 2673 2674 /* If we reach the seperator then stop applying the stack */ 2675 if (foreach_copy->result_type == IS_UNUSED && foreach_copy->op1_type == IS_UNUSED) { 2676 return 1; 2677 } 2678 2679 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2680 2681 opline->opcode = (foreach_copy->result_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; 2682 COPY_NODE(opline->op1, foreach_copy->result); 2683 SET_UNUSED(opline->op2); 2684 opline->extended_value = 1; 2685 2686 if (foreach_copy->op1_type != IS_UNUSED) { 2687 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2688 2689 opline->opcode = (foreach_copy->op1_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; 2690 COPY_NODE(opline->op1, foreach_copy->op1); 2691 SET_UNUSED(opline->op2); 2692 opline->extended_value = 0; 2693 } 2694 2695 return 0; 2696} 2697/* }}} */ 2698 2699void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */ 2700{ 2701 zend_op *opline; 2702 int start_op_number, end_op_number; 2703 zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; 2704 2705 /* The error for use of return inside a generator is thrown in pass_two. */ 2706 2707 if (do_end_vparse) { 2708 if (returns_reference && !zend_is_function_or_method_call(expr)) { 2709 zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC); 2710 } else { 2711 zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC); 2712 } 2713 } 2714 2715 start_op_number = get_next_op_number(CG(active_op_array)); 2716 2717#ifdef ZTS 2718 zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr TSRMLS_CC); 2719 zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy TSRMLS_CC); 2720#else 2721 zend_stack_apply(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_switch_expr); 2722 zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy); 2723#endif 2724 2725 end_op_number = get_next_op_number(CG(active_op_array)); 2726 while (start_op_number < end_op_number) { 2727 CG(active_op_array)->opcodes[start_op_number].extended_value |= EXT_TYPE_FREE_ON_RETURN; 2728 start_op_number++; 2729 } 2730 2731 if (CG(context).in_finally) { 2732 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2733 opline->opcode = ZEND_DISCARD_EXCEPTION; 2734 SET_UNUSED(opline->op1); 2735 SET_UNUSED(opline->op2); 2736 } 2737 2738 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2739 2740 opline->opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN; 2741 2742 if (expr) { 2743 SET_NODE(opline->op1, expr); 2744 2745 if (do_end_vparse && zend_is_function_or_method_call(expr)) { 2746 opline->extended_value = ZEND_RETURNS_FUNCTION; 2747 } 2748 } else { 2749 opline->op1_type = IS_CONST; 2750 LITERAL_NULL(opline->op1); 2751 } 2752 2753 SET_UNUSED(opline->op2); 2754} 2755/* }}} */ 2756 2757void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_variable TSRMLS_DC) /* {{{ */ 2758{ 2759 zend_op *opline; 2760 2761 if (!CG(active_op_array)->function_name) { 2762 zend_error(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a function"); 2763 } 2764 2765 CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR; 2766 2767 if (is_variable) { 2768 if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(value)) { 2769 zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC); 2770 } else { 2771 zend_do_end_variable_parse(value, BP_VAR_R, 0 TSRMLS_CC); 2772 } 2773 } 2774 2775 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2776 2777 opline->opcode = ZEND_YIELD; 2778 2779 if (value) { 2780 SET_NODE(opline->op1, value); 2781 2782 if (is_variable && zend_is_function_or_method_call(value)) { 2783 opline->extended_value = ZEND_RETURNS_FUNCTION; 2784 } 2785 } else { 2786 SET_UNUSED(opline->op1); 2787 } 2788 2789 if (key) { 2790 SET_NODE(opline->op2, key); 2791 } else { 2792 SET_UNUSED(opline->op2); 2793 } 2794 2795 opline->result_type = IS_TMP_VAR; 2796 opline->result.var = get_temporary_variable(CG(active_op_array)); 2797 GET_NODE(result, opline->result); 2798} 2799/* }}} */ 2800 2801static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */ 2802{ 2803 int try_catch_offset = CG(active_op_array)->last_try_catch++; 2804 2805 CG(active_op_array)->try_catch_array = erealloc(CG(active_op_array)->try_catch_array, sizeof(zend_try_catch_element)*CG(active_op_array)->last_try_catch); 2806 CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op; 2807 CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = 0; 2808 CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = 0; 2809 CG(active_op_array)->try_catch_array[try_catch_offset].finally_end = 0; 2810 return try_catch_offset; 2811} 2812/* }}} */ 2813 2814static void zend_add_catch_element(int offset, zend_uint catch_op TSRMLS_DC) /* {{{ */ 2815{ 2816 CG(active_op_array)->try_catch_array[offset].catch_op = catch_op; 2817} 2818/* }}} */ 2819 2820void zend_do_first_catch(znode *open_parentheses TSRMLS_DC) /* {{{ */ 2821{ 2822 open_parentheses->u.op.opline_num = get_next_op_number(CG(active_op_array)); 2823} 2824/* }}} */ 2825 2826void zend_initialize_try_catch_element(znode *catch_token TSRMLS_DC) /* {{{ */ 2827{ 2828 int jmp_op_number = get_next_op_number(CG(active_op_array)); 2829 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2830 zend_llist jmp_list; 2831 zend_llist *jmp_list_ptr; 2832 2833 opline->opcode = ZEND_JMP; 2834 SET_UNUSED(opline->op1); 2835 SET_UNUSED(opline->op2); 2836 /* save for backpatching */ 2837 2838 zend_llist_init(&jmp_list, sizeof(int), NULL, 0); 2839 zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist)); 2840 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); 2841 zend_llist_add_element(jmp_list_ptr, &jmp_op_number); 2842 2843 catch_token->EA = get_next_op_number(CG(active_op_array)); 2844} 2845/* }}} */ 2846 2847void zend_do_mark_last_catch(const znode *first_catch, const znode *last_additional_catch TSRMLS_DC) /* {{{ */ 2848{ 2849 CG(active_op_array)->last--; 2850 zend_do_if_end(TSRMLS_C); 2851 if (last_additional_catch->u.op.opline_num == -1) { 2852 CG(active_op_array)->opcodes[first_catch->u.op.opline_num].result.num = 1; 2853 CG(active_op_array)->opcodes[first_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); 2854 } else { 2855 CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].result.num = 1; 2856 CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); 2857 } 2858 DEC_BPC(CG(active_op_array)); 2859} 2860/* }}} */ 2861 2862void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */ 2863{ 2864 try_token->u.op.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC); 2865 INC_BPC(CG(active_op_array)); 2866} 2867/* }}} */ 2868 2869void zend_do_finally(znode *finally_token TSRMLS_DC) /* {{{ */ 2870{ 2871 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2872 2873 finally_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); 2874 /* call the the "finally" block */ 2875 opline->opcode = ZEND_FAST_CALL; 2876 SET_UNUSED(opline->op1); 2877 opline->op1.opline_num = finally_token->u.op.opline_num + 1; 2878 SET_UNUSED(opline->op2); 2879 /* jump to code after the "finally" block, 2880 * the actual jump address is going to be set in zend_do_end_finally() 2881 */ 2882 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2883 opline->opcode = ZEND_JMP; 2884 SET_UNUSED(opline->op1); 2885 SET_UNUSED(opline->op2); 2886 2887 CG(context).in_finally++; 2888} 2889/* }}} */ 2890 2891void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */ 2892{ 2893 long catch_op_number; 2894 zend_op *opline; 2895 znode catch_class; 2896 2897 if (class_name->op_type == IS_CONST && 2898 ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { 2899 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC); 2900 catch_class = *class_name; 2901 } else { 2902 zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement"); 2903 } 2904 2905 catch_op_number = get_next_op_number(CG(active_op_array)); 2906 if (first_catch) { 2907 first_catch->u.op.opline_num = catch_op_number; 2908 } 2909 2910 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2911 opline->opcode = ZEND_CATCH; 2912 opline->op1_type = IS_CONST; 2913 opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), &catch_class.u.constant TSRMLS_CC); 2914 opline->op2_type = IS_CV; 2915 opline->op2.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len, 0 TSRMLS_CC); 2916 Z_STRVAL(catch_var->u.constant) = (char*)CG(active_op_array)->vars[opline->op2.var].name; 2917 opline->result.num = 0; /* 1 means it's the last catch in the block */ 2918 2919 catch_token->u.op.opline_num = catch_op_number; 2920} 2921/* }}} */ 2922 2923void zend_do_end_catch(znode *catch_token TSRMLS_DC) /* {{{ */ 2924{ 2925 int jmp_op_number = get_next_op_number(CG(active_op_array)); 2926 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2927 zend_llist *jmp_list_ptr; 2928 2929 opline->opcode = ZEND_JMP; 2930 SET_UNUSED(opline->op1); 2931 SET_UNUSED(opline->op2); 2932 /* save for backpatching */ 2933 2934 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); 2935 zend_llist_add_element(jmp_list_ptr, &jmp_op_number); 2936 2937 CG(active_op_array)->opcodes[catch_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); 2938} 2939/* }}} */ 2940 2941void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC) /* {{{ */ { 2942 if (catch_token->op_type != IS_UNUSED) { 2943 zend_add_catch_element(try_token->u.op.opline_num, catch_token->EA TSRMLS_CC); 2944 } 2945} 2946/* }}} */ 2947 2948void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC) /* {{{ */ 2949{ 2950 if (catch_token->op_type == IS_UNUSED && finally_token->op_type == IS_UNUSED) { 2951 zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally"); 2952 } 2953 if (finally_token->op_type != IS_UNUSED) { 2954 zend_op *opline; 2955 2956 CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num + 1; 2957 CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array)); 2958 CG(active_op_array)->has_finally_block = 1; 2959 2960 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2961 opline->opcode = ZEND_FAST_RET; 2962 SET_UNUSED(opline->op1); 2963 SET_UNUSED(opline->op2); 2964 2965 CG(active_op_array)->opcodes[finally_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array)); 2966 2967 CG(context).in_finally--; 2968 } 2969} 2970/* }}} */ 2971 2972void zend_do_throw(const znode *expr TSRMLS_DC) /* {{{ */ 2973{ 2974 zend_op *opline; 2975 2976 opline = get_next_op(CG(active_op_array) TSRMLS_CC); 2977 opline->opcode = ZEND_THROW; 2978 SET_NODE(opline->op1, expr); 2979 SET_UNUSED(opline->op2); 2980} 2981/* }}} */ 2982 2983ZEND_API void function_add_ref(zend_function *function) /* {{{ */ 2984{ 2985 if (function->type == ZEND_USER_FUNCTION) { 2986 zend_op_array *op_array = &function->op_array; 2987 2988 (*op_array->refcount)++; 2989 if (op_array->static_variables) { 2990 HashTable *static_variables = op_array->static_variables; 2991 zval *tmp_zval; 2992 2993 ALLOC_HASHTABLE(op_array->static_variables); 2994 zend_hash_init(op_array->static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0); 2995 zend_hash_copy(op_array->static_variables, static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_zval, sizeof(zval *)); 2996 } 2997 op_array->run_time_cache = NULL; 2998 } 2999} 3000/* }}} */ 3001 3002static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ 3003{ 3004 zend_function *function, *new_function; 3005 3006 if (!ce->parent) { 3007 return; 3008 } 3009 3010 /* You cannot change create_object */ 3011 ce->create_object = ce->parent->create_object; 3012 3013 /* Inherit special functions if needed */ 3014 if (!ce->get_iterator) { 3015 ce->get_iterator = ce->parent->get_iterator; 3016 } 3017 if (!ce->iterator_funcs.funcs) { 3018 ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs; 3019 } 3020 if (!ce->__get) { 3021 ce->__get = ce->parent->__get; 3022 } 3023 if (!ce->__set) { 3024 ce->__set = ce->parent->__set; 3025 } 3026 if (!ce->__unset) { 3027 ce->__unset = ce->parent->__unset; 3028 } 3029 if (!ce->__isset) { 3030 ce->__isset = ce->parent->__isset; 3031 } 3032 if (!ce->__call) { 3033 ce->__call = ce->parent->__call; 3034 } 3035 if (!ce->__callstatic) { 3036 ce->__callstatic = ce->parent->__callstatic; 3037 } 3038 if (!ce->__tostring) { 3039 ce->__tostring = ce->parent->__tostring; 3040 } 3041 if (!ce->clone) { 3042 ce->clone = ce->parent->clone; 3043 } 3044 if(!ce->serialize) { 3045 ce->serialize = ce->parent->serialize; 3046 } 3047 if(!ce->unserialize) { 3048 ce->unserialize = ce->parent->unserialize; 3049 } 3050 if (!ce->destructor) { 3051 ce->destructor = ce->parent->destructor; 3052 } 3053 if (ce->constructor) { 3054 if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) { 3055 zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()", 3056 ce->parent->name, ce->parent->constructor->common.function_name, 3057 ce->name, ce->constructor->common.function_name 3058 ); 3059 } 3060 return; 3061 } 3062 3063 if (zend_hash_find(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), (void **)&function)==SUCCESS) { 3064 /* inherit parent's constructor */ 3065 zend_hash_update(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), function, sizeof(zend_function), (void**)&new_function); 3066 function_add_ref(new_function); 3067 } else { 3068 /* Don't inherit the old style constructor if we already have the new style constructor */ 3069 char *lc_class_name; 3070 char *lc_parent_class_name; 3071 3072 lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length); 3073 if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) { 3074 lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length); 3075 if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) && 3076 zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) { 3077 if (function->common.fn_flags & ZEND_ACC_CTOR) { 3078 /* inherit parent's constructor */ 3079 zend_hash_update(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1, function, sizeof(zend_function), (void**)&new_function); 3080 function_add_ref(new_function); 3081 } 3082 } 3083 efree(lc_parent_class_name); 3084 } 3085 efree(lc_class_name); 3086 } 3087 ce->constructor = ce->parent->constructor; 3088} 3089/* }}} */ 3090 3091char *zend_visibility_string(zend_uint fn_flags) /* {{{ */ 3092{ 3093 if (fn_flags & ZEND_ACC_PRIVATE) { 3094 return "private"; 3095 } 3096 if (fn_flags & ZEND_ACC_PROTECTED) { 3097 return "protected"; 3098 } 3099 if (fn_flags & ZEND_ACC_PUBLIC) { 3100 return "public"; 3101 } 3102 return ""; 3103} 3104/* }}} */ 3105 3106static void do_inherit_method(zend_function *function) /* {{{ */ 3107{ 3108 /* The class entry of the derived function intentionally remains the same 3109 * as that of the parent class. That allows us to know in which context 3110 * we're running, and handle private method calls properly. 3111 */ 3112 function_add_ref(function); 3113} 3114/* }}} */ 3115 3116static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */ 3117{ 3118 zend_uint i; 3119 3120 /* If it's a user function then arg_info == NULL means we don't have any parameters but 3121 * we still need to do the arg number checks. We are only willing to ignore this for internal 3122 * functions because extensions don't always define arg_info. 3123 */ 3124 if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) { 3125 return 1; 3126 } 3127 3128 /* Checks for constructors only if they are declared in an interface, 3129 * or explicitly marked as abstract 3130 */ 3131 if ((fe->common.fn_flags & ZEND_ACC_CTOR) 3132 && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0 3133 && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) { 3134 return 1; 3135 } 3136 3137 /* If both methods are private do not enforce a signature */ 3138 if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) { 3139 return 1; 3140 } 3141 3142 /* check number of arguments */ 3143 if (proto->common.required_num_args < fe->common.required_num_args 3144 || proto->common.num_args > fe->common.num_args) { 3145 return 0; 3146 } 3147 3148 if (fe->common.type != ZEND_USER_FUNCTION 3149 && (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) != 0 3150 && (fe->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) == 0) { 3151 return 0; 3152 } 3153 3154 /* by-ref constraints on return values are covariant */ 3155 if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) 3156 && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { 3157 return 0; 3158 } 3159 3160 for (i=0; i < proto->common.num_args; i++) { 3161 if (ZEND_LOG_XOR(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)) { 3162 /* Only one has a type hint and the other one doesn't */ 3163 return 0; 3164 } 3165 3166 if (fe->common.arg_info[i].class_name) { 3167 const char *fe_class_name, *proto_class_name; 3168 zend_uint fe_class_name_len, proto_class_name_len; 3169 3170 if (!strcasecmp(fe->common.arg_info[i].class_name, "parent") && proto->common.scope) { 3171 fe_class_name = proto->common.scope->name; 3172 fe_class_name_len = proto->common.scope->name_length; 3173 } else if (!strcasecmp(fe->common.arg_info[i].class_name, "self") && fe->common.scope) { 3174 fe_class_name = fe->common.scope->name; 3175 fe_class_name_len = fe->common.scope->name_length; 3176 } else { 3177 fe_class_name = fe->common.arg_info[i].class_name; 3178 fe_class_name_len = fe->common.arg_info[i].class_name_len; 3179 } 3180 3181 if (!strcasecmp(proto->common.arg_info[i].class_name, "parent") && proto->common.scope && proto->common.scope->parent) { 3182 proto_class_name = proto->common.scope->parent->name; 3183 proto_class_name_len = proto->common.scope->parent->name_length; 3184 } else if (!strcasecmp(proto->common.arg_info[i].class_name, "self") && proto->common.scope) { 3185 proto_class_name = proto->common.scope->name; 3186 proto_class_name_len = proto->common.scope->name_length; 3187 } else { 3188 proto_class_name = proto->common.arg_info[i].class_name; 3189 proto_class_name_len = proto->common.arg_info[i].class_name_len; 3190 } 3191 3192 if (strcasecmp(fe_class_name, proto_class_name)!=0) { 3193 const char *colon; 3194 3195 if (fe->common.type != ZEND_USER_FUNCTION) { 3196 return 0; 3197 } else if (strchr(proto_class_name, '\\') != NULL || 3198 (colon = zend_memrchr(fe_class_name, '\\', fe_class_name_len)) == NULL || 3199 strcasecmp(colon+1, proto_class_name) != 0) { 3200 zend_class_entry **fe_ce, **proto_ce; 3201 int found, found2; 3202 3203 found = zend_lookup_class(fe_class_name, fe_class_name_len, &fe_ce TSRMLS_CC); 3204 found2 = zend_lookup_class(proto_class_name, proto_class_name_len, &proto_ce TSRMLS_CC); 3205 3206 /* Check for class alias */ 3207 if (found != SUCCESS || found2 != SUCCESS || 3208 (*fe_ce)->type == ZEND_INTERNAL_CLASS || 3209 (*proto_ce)->type == ZEND_INTERNAL_CLASS || 3210 *fe_ce != *proto_ce) { 3211 return 0; 3212 } 3213 } 3214 } 3215 } 3216 if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) { 3217 /* Incompatible type hint */ 3218 return 0; 3219 } 3220 3221 /* by-ref constraints on arguments are invariant */ 3222 if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) { 3223 return 0; 3224 } 3225 } 3226 3227 if (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) { 3228 for (i=proto->common.num_args; i < fe->common.num_args; i++) { 3229 if (!fe->common.arg_info[i].pass_by_reference) { 3230 return 0; 3231 } 3232 } 3233 } 3234 return 1; 3235} 3236/* }}} */ 3237 3238#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \ 3239 if (UNEXPECTED(offset - buf + size >= length)) { \ 3240 length += size + 1; \ 3241 buf = erealloc(buf, length); \ 3242 } 3243 3244static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */ 3245{ 3246 char *offset, *buf; 3247 zend_uint length = 1024; 3248 3249 offset = buf = (char *)emalloc(length * sizeof(char)); 3250 if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { 3251 *(offset++) = '&'; 3252 *(offset++) = ' '; 3253 } 3254 3255 if (fptr->common.scope) { 3256 memcpy(offset, fptr->common.scope->name, fptr->common.scope->name_length); 3257 offset += fptr->common.scope->name_length; 3258 *(offset++) = ':'; 3259 *(offset++) = ':'; 3260 } 3261 3262 { 3263 size_t name_len = strlen(fptr->common.function_name); 3264 REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len); 3265 memcpy(offset, fptr->common.function_name, name_len); 3266 offset += name_len; 3267 } 3268 3269 *(offset++) = '('; 3270 if (fptr->common.arg_info) { 3271 zend_uint i, required; 3272 zend_arg_info *arg_info = fptr->common.arg_info; 3273 3274 required = fptr->common.required_num_args; 3275 for (i = 0; i < fptr->common.num_args;) { 3276 if (arg_info->class_name) { 3277 const char *class_name; 3278 zend_uint class_name_len; 3279 if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) { 3280 class_name = fptr->common.scope->name; 3281 class_name_len = fptr->common.scope->name_length; 3282 } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) { 3283 class_name = fptr->common.scope->parent->name; 3284 class_name_len = fptr->common.scope->parent->name_length; 3285 } else { 3286 class_name = arg_info->class_name; 3287 class_name_len = arg_info->class_name_len; 3288 } 3289 REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len); 3290 memcpy(offset, class_name, class_name_len); 3291 offset += class_name_len; 3292 *(offset++) = ' '; 3293 } else if (arg_info->type_hint) { 3294 zend_uint type_name_len; 3295 char *type_name = zend_get_type_by_const(arg_info->type_hint); 3296 type_name_len = strlen(type_name); 3297 REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len); 3298 memcpy(offset, type_name, type_name_len); 3299 offset += type_name_len; 3300 *(offset++) = ' '; 3301 } 3302 3303 if (arg_info->pass_by_reference) { 3304 *(offset++) = '&'; 3305 } 3306 *(offset++) = '$'; 3307 3308 if (arg_info->name) { 3309 REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len); 3310 memcpy(offset, arg_info->name, arg_info->name_len); 3311 offset += arg_info->name_len; 3312 } else { 3313 zend_uint idx = i; 3314 memcpy(offset, "param", 5); 3315 offset += 5; 3316 do { 3317 *(offset++) = (char) (idx % 10) + '0'; 3318 idx /= 10; 3319 } while (idx > 0); 3320 } 3321 if (i >= required) { 3322 *(offset++) = ' '; 3323 *(offset++) = '='; 3324 *(offset++) = ' '; 3325 if (fptr->type == ZEND_USER_FUNCTION) { 3326 zend_op *precv = NULL; 3327 { 3328 zend_uint idx = i; 3329 zend_op *op = ((zend_op_array *)fptr)->opcodes; 3330 zend_op *end = op + ((zend_op_array *)fptr)->last; 3331 3332 ++idx; 3333 while (op < end) { 3334 if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT) 3335 && op->op1.num == (long)idx) 3336 { 3337 precv = op; 3338 } 3339 ++op; 3340 } 3341 } 3342 if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { 3343 zval *zv, zv_copy; 3344 int use_copy; 3345 ALLOC_ZVAL(zv); 3346 *zv = *precv->op2.zv; 3347 zval_copy_ctor(zv); 3348 INIT_PZVAL(zv); 3349 zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC); 3350 if (Z_TYPE_P(zv) == IS_BOOL) { 3351 if (Z_LVAL_P(zv)) { 3352 memcpy(offset, "true", 4); 3353 offset += 4; 3354 } else { 3355 memcpy(offset, "false", 5); 3356 offset += 5; 3357 } 3358 } else if (Z_TYPE_P(zv) == IS_NULL) { 3359 memcpy(offset, "NULL", 4); 3360 offset += 4; 3361 } else if (Z_TYPE_P(zv) == IS_STRING) { 3362 *(offset++) = '\''; 3363 REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10)); 3364 memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10)); 3365 offset += MIN(Z_STRLEN_P(zv), 10); 3366 if (Z_STRLEN_P(zv) > 10) { 3367 *(offset++) = '.'; 3368 *(offset++) = '.'; 3369 *(offset++) = '.'; 3370 } 3371 *(offset++) = '\''; 3372 } else if (Z_TYPE_P(zv) == IS_ARRAY) { 3373 memcpy(offset, "Array", 5); 3374 offset += 5; 3375 } else { 3376 zend_make_printable_zval(zv, &zv_copy, &use_copy); 3377 REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN(zv_copy)); 3378 memcpy(offset, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy)); 3379 offset += Z_STRLEN(zv_copy); 3380 if (use_copy) { 3381 zval_dtor(&zv_copy); 3382 } 3383 } 3384 zval_ptr_dtor(&zv); 3385 } 3386 } else { 3387 memcpy(offset, "NULL", 4); 3388 offset += 4; 3389 } 3390 } 3391 3392 if (++i < fptr->common.num_args) { 3393 *(offset++) = ','; 3394 *(offset++) = ' '; 3395 } 3396 arg_info++; 3397 REALLOC_BUF_IF_EXCEED(buf, offset, length, 32); 3398 } 3399 } 3400 *(offset++) = ')'; 3401 *offset = '\0'; 3402 3403 return buf; 3404} 3405/* }}} */ 3406 3407static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */ 3408{ 3409 zend_uint child_flags; 3410 zend_uint parent_flags = parent->common.fn_flags; 3411 3412 if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0 3413 && parent->common.fn_flags & ZEND_ACC_ABSTRACT 3414 && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope) 3415 && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) { 3416 zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)", 3417 parent->common.scope->name, 3418 child->common.function_name, 3419 child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name); 3420 } 3421 3422 if (parent_flags & ZEND_ACC_FINAL) { 3423 zend_error(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name); 3424 } 3425 3426 child_flags = child->common.fn_flags; 3427 /* You cannot change from static to non static and vice versa. 3428 */ 3429 if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) { 3430 if (child->common.fn_flags & ZEND_ACC_STATIC) { 3431 zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); 3432 } else { 3433 zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); 3434 } 3435 } 3436 3437 /* Disallow making an inherited method abstract. */ 3438 if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) { 3439 zend_error(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); 3440 } 3441 3442 if (parent_flags & ZEND_ACC_CHANGED) { 3443 child->common.fn_flags |= ZEND_ACC_CHANGED; 3444 } else { 3445 /* Prevent derived classes from restricting access that was available in parent classes 3446 */ 3447 if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) { 3448 zend_error(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); 3449 } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK)) 3450 && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) { 3451 child->common.fn_flags |= ZEND_ACC_CHANGED; 3452 } 3453 } 3454 3455 if (parent_flags & ZEND_ACC_PRIVATE) { 3456 child->common.prototype = NULL; 3457 } else if (parent_flags & ZEND_ACC_ABSTRACT) { 3458 child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT; 3459 child->common.prototype = parent; 3460 } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) { 3461 /* ctors only have a prototype if it comes from an interface */ 3462 child->common.prototype = parent->common.prototype ? parent->common.prototype : parent; 3463 } 3464 3465 if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) { 3466 if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) { 3467 zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC)); 3468 } 3469 } else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */ 3470 if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) { 3471 char *method_prototype = zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC); 3472 zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype); 3473 efree(method_prototype); 3474 } 3475 } 3476} 3477/* }}} */ 3478 3479static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, const zend_hash_key *hash_key, zend_class_entry *child_ce) /* {{{ */ 3480{ 3481 zend_uint parent_flags = parent->common.fn_flags; 3482 zend_function *child; 3483 TSRMLS_FETCH(); 3484 3485 if (zend_hash_quick_find(child_function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child)==FAILURE) { 3486 if (parent_flags & (ZEND_ACC_ABSTRACT)) { 3487 child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; 3488 } 3489 return 1; /* method doesn't exist in child, copy from parent */ 3490 } 3491 3492 do_inheritance_check_on_method(child, parent TSRMLS_CC); 3493 3494 return 0; 3495} 3496/* }}} */ 3497 3498static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, const zend_hash_key *hash_key, zend_class_entry *ce) /* {{{ */ 3499{ 3500 zend_property_info *child_info; 3501 zend_class_entry *parent_ce = ce->parent; 3502 3503 if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) { 3504 if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) { 3505 child_info->flags |= ZEND_ACC_CHANGED; 3506 } else { 3507 zend_hash_quick_update(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, parent_info, sizeof(zend_property_info), (void **) &child_info); 3508 if(ce->type & ZEND_INTERNAL_CLASS) { 3509 zend_duplicate_property_info_internal(child_info); 3510 } else { 3511 zend_duplicate_property_info(child_info); 3512 } 3513 child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */ 3514 child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */ 3515 } 3516 return 0; /* don't copy access information to child */ 3517 } 3518 3519 if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) { 3520 if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) { 3521 zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s", 3522 (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey, 3523 (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey); 3524 3525 } 3526 3527 if(parent_info->flags & ZEND_ACC_CHANGED) { 3528 child_info->flags |= ZEND_ACC_CHANGED; 3529 } 3530 3531 if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) { 3532 zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); 3533 } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) { 3534 zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset])); 3535 ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset]; 3536 ce->default_properties_table[child_info->offset] = NULL; 3537 child_info->offset = parent_info->offset; 3538 } 3539 return 0; /* Don't copy from parent */ 3540 } else { 3541 return 1; /* Copy from parent */ 3542 } 3543} 3544/* }}} */ 3545 3546static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */ 3547{ 3548 if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) { 3549 zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name, iface->name); 3550 } 3551 if (ce == iface) { 3552 zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name); 3553 } 3554} 3555/* }}} */ 3556 3557ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */ 3558{ 3559 /* expects interface to be contained in ce's interface list already */ 3560 zend_uint i, ce_num, if_num = iface->num_interfaces; 3561 zend_class_entry *entry; 3562 3563 if (if_num==0) { 3564 return; 3565 } 3566 ce_num = ce->num_interfaces; 3567 3568 if (ce->type == ZEND_INTERNAL_CLASS) { 3569 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num)); 3570 } else { 3571 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num)); 3572 } 3573 3574 /* Inherit the interfaces, only if they're not already inherited by the class */ 3575 while (if_num--) { 3576 entry = iface->interfaces[if_num]; 3577 for (i = 0; i < ce_num; i++) { 3578 if (ce->interfaces[i] == entry) { 3579 break; 3580 } 3581 } 3582 if (i == ce_num) { 3583 ce->interfaces[ce->num_interfaces++] = entry; 3584 } 3585 } 3586 3587 /* and now call the implementing handlers */ 3588 while (ce_num < ce->num_interfaces) { 3589 do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC); 3590 } 3591} 3592/* }}} */ 3593 3594#ifdef ZTS 3595static void zval_internal_ctor(zval **p) /* {{{ */ 3596{ 3597 zval *orig_ptr = *p; 3598 3599 ALLOC_ZVAL(*p); 3600 MAKE_COPY_ZVAL(&orig_ptr, *p); 3601} 3602/* }}} */ 3603 3604# define zval_property_ctor(parent_ce, ce) \ 3605 ((void (*)(void *)) (((parent_ce)->type != (ce)->type) ? zval_internal_ctor : zval_add_ref)) 3606#else 3607# define zval_property_ctor(parent_ce, ce) \ 3608 ((void (*)(void *)) zval_add_ref) 3609#endif 3610 3611ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */ 3612{ 3613 zend_property_info *property_info; 3614 3615 if ((ce->ce_flags & ZEND_ACC_INTERFACE) 3616 && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) { 3617 zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name); 3618 } 3619 if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) { 3620 zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name); 3621 } 3622 3623 ce->parent = parent_ce; 3624 /* Copy serialize/unserialize callbacks */ 3625 if (!ce->serialize) { 3626 ce->serialize = parent_ce->serialize; 3627 } 3628 if (!ce->unserialize) { 3629 ce->unserialize = parent_ce->unserialize; 3630 } 3631 3632 /* Inherit interfaces */ 3633 zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC); 3634 3635 /* Inherit properties */ 3636 if (parent_ce->default_properties_count) { 3637 int i = ce->default_properties_count + parent_ce->default_properties_count; 3638 3639 ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS); 3640 if (ce->default_properties_count) { 3641 while (i-- > parent_ce->default_properties_count) { 3642 ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count]; 3643 } 3644 } 3645 for (i = 0; i < parent_ce->default_properties_count; i++) { 3646 ce->default_properties_table[i] = parent_ce->default_properties_table[i]; 3647 if (ce->default_properties_table[i]) { 3648#ifdef ZTS 3649 if (parent_ce->type != ce->type) { 3650 zval *p; 3651 3652 ALLOC_ZVAL(p); 3653 MAKE_COPY_ZVAL(&ce->default_properties_table[i], p); 3654 ce->default_properties_table[i] = p; 3655 } else { 3656 Z_ADDREF_P(ce->default_properties_table[i]); 3657 } 3658#else 3659 Z_ADDREF_P(ce->default_properties_table[i]); 3660#endif 3661 } 3662 } 3663 ce->default_properties_count += parent_ce->default_properties_count; 3664 } 3665 3666 if (parent_ce->type != ce->type) { 3667 /* User class extends internal class */ 3668 zend_update_class_constants(parent_ce TSRMLS_CC); 3669 if (parent_ce->default_static_members_count) { 3670 int i = ce->default_static_members_count + parent_ce->default_static_members_count; 3671 3672 ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(void*) * i); 3673 if (ce->default_static_members_count) { 3674 while (i-- > parent_ce->default_static_members_count) { 3675 ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count]; 3676 } 3677 } 3678 for (i = 0; i < parent_ce->default_static_members_count; i++) { 3679 SEPARATE_ZVAL_TO_MAKE_IS_REF(&CE_STATIC_MEMBERS(parent_ce)[i]); 3680 ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i]; 3681 Z_ADDREF_P(ce->default_static_members_table[i]); 3682 } 3683 ce->default_static_members_count += parent_ce->default_static_members_count; 3684 ce->static_members_table = ce->default_static_members_table; 3685 } 3686 } else { 3687 if (parent_ce->default_static_members_count) { 3688 int i = ce->default_static_members_count + parent_ce->default_static_members_count; 3689 3690 ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS); 3691 if (ce->default_static_members_count) { 3692 while (i-- > parent_ce->default_static_members_count) { 3693 ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count]; 3694 } 3695 } 3696 for (i = 0; i < parent_ce->default_static_members_count; i++) { 3697 SEPARATE_ZVAL_TO_MAKE_IS_REF(&parent_ce->default_static_members_table[i]); 3698 ce->default_static_members_table[i] = parent_ce->default_static_members_table[i]; 3699 Z_ADDREF_P(ce->default_static_members_table[i]); 3700 } 3701 ce->default_static_members_count += parent_ce->default_static_members_count; 3702 if (ce->type == ZEND_USER_CLASS) { 3703 ce->static_members_table = ce->default_static_members_table; 3704 } 3705 } 3706 } 3707 3708 for (zend_hash_internal_pointer_reset(&ce->properties_info); 3709 zend_hash_get_current_data(&ce->properties_info, (void *) &property_info) == SUCCESS; 3710 zend_hash_move_forward(&ce->properties_info)) { 3711 if (property_info->ce == ce) { 3712 if (property_info->flags & ZEND_ACC_STATIC) { 3713 property_info->offset += parent_ce->default_static_members_count; 3714 } else { 3715 property_info->offset += parent_ce->default_properties_count; 3716 } 3717 } 3718 } 3719 3720 zend_hash_merge_ex(&ce->properties_info, &parent_ce->properties_info, (copy_ctor_func_t) (ce->type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal : zend_duplicate_property_info), sizeof(zend_property_info), (merge_checker_func_t) do_inherit_property_access_check, ce); 3721 3722 zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, zval_property_ctor(parent_ce, ce), NULL, sizeof(zval *), 0); 3723 zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce); 3724 do_inherit_parent_constructor(ce); 3725 3726 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) { 3727 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; 3728 } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) { 3729 /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */ 3730 zend_verify_abstract_class(ce TSRMLS_CC); 3731 } 3732 ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS; 3733} 3734/* }}} */ 3735 3736static zend_bool do_inherit_constant_check(HashTable *child_constants_table, const zval **parent_constant, const zend_hash_key *hash_key, const zend_class_entry *iface) /* {{{ */ 3737{ 3738 zval **old_constant; 3739 3740 if (zend_hash_quick_find(child_constants_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**)&old_constant) == SUCCESS) { 3741 if (*old_constant != *parent_constant) { 3742 zend_error(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", hash_key->arKey, iface->name); 3743 } 3744 return 0; 3745 } 3746 return 1; 3747} 3748/* }}} */ 3749 3750static int do_interface_constant_check(zval **val TSRMLS_DC, int num_args, va_list args, const zend_hash_key *key) /* {{{ */ 3751{ 3752 zend_class_entry **iface = va_arg(args, zend_class_entry**); 3753 3754 do_inherit_constant_check(&(*iface)->constants_table, (const zval **) val, key, *iface); 3755 3756 return ZEND_HASH_APPLY_KEEP; 3757} 3758/* }}} */ 3759 3760ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */ 3761{ 3762 zend_uint i, ignore = 0; 3763 zend_uint current_iface_num = ce->num_interfaces; 3764 zend_uint parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0; 3765 3766 for (i = 0; i < ce->num_interfaces; i++) { 3767 if (ce->interfaces[i] == NULL) { 3768 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i)); 3769 i--; 3770 } else if (ce->interfaces[i] == iface) { 3771 if (i < parent_iface_num) { 3772 ignore = 1; 3773 } else { 3774 zend_error(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name, iface->name); 3775 } 3776 } 3777 } 3778 if (ignore) { 3779 /* Check for attempt to redeclare interface constants */ 3780 zend_hash_apply_with_arguments(&ce->constants_table TSRMLS_CC, (apply_func_args_t) do_interface_constant_check, 1, &iface); 3781 } else { 3782 if (ce->num_interfaces >= current_iface_num) { 3783 if (ce->type == ZEND_INTERNAL_CLASS) { 3784 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num)); 3785 } else { 3786 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num)); 3787 } 3788 } 3789 ce->interfaces[ce->num_interfaces++] = iface; 3790 3791 zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface); 3792 zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce); 3793 3794 do_implement_interface(ce, iface TSRMLS_CC); 3795 zend_do_inherit_interfaces(ce, iface TSRMLS_CC); 3796 } 3797} 3798/* }}} */ 3799 3800ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */ 3801{ 3802 zend_uint i, ignore = 0; 3803 zend_uint current_trait_num = ce->num_traits; 3804 zend_uint parent_trait_num = ce->parent ? ce->parent->num_traits : 0; 3805 3806 for (i = 0; i < ce->num_traits; i++) { 3807 if (ce->traits[i] == NULL) { 3808 memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i)); 3809 i--; 3810 } else if (ce->traits[i] == trait) { 3811 if (i < parent_trait_num) { 3812 ignore = 1; 3813 } 3814 } 3815 } 3816 if (!ignore) { 3817 if (ce->num_traits >= current_trait_num) { 3818 if (ce->type == ZEND_INTERNAL_CLASS) { 3819 ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num)); 3820 } else { 3821 ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num)); 3822 } 3823 } 3824 ce->traits[ce->num_traits++] = trait; 3825 } 3826} 3827/* }}} */ 3828 3829static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */ 3830{ 3831 zend_uint fn_flags = fn->common.scope->ce_flags; 3832 zend_uint other_flags = other_fn->common.scope->ce_flags; 3833 3834 return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC) 3835 && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC)) 3836 && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) == 3837 (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */ 3838} 3839/* }}} */ 3840 3841static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint mname_len, zend_function* fe TSRMLS_DC) /* {{{ */ 3842{ 3843 if (!strncmp(mname, ZEND_CLONE_FUNC_NAME, mname_len)) { 3844 ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE; 3845 } else if (!strncmp(mname, ZEND_CONSTRUCTOR_FUNC_NAME, mname_len)) { 3846 if (ce->constructor) { 3847 zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name); 3848 } 3849 ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR; 3850 } else if (!strncmp(mname, ZEND_DESTRUCTOR_FUNC_NAME, mname_len)) { 3851 ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR; 3852 } else if (!strncmp(mname, ZEND_GET_FUNC_NAME, mname_len)) { 3853 ce->__get = fe; 3854 } else if (!strncmp(mname, ZEND_SET_FUNC_NAME, mname_len)) { 3855 ce->__set = fe; 3856 } else if (!strncmp(mname, ZEND_CALL_FUNC_NAME, mname_len)) { 3857 ce->__call = fe; 3858 } else if (!strncmp(mname, ZEND_UNSET_FUNC_NAME, mname_len)) { 3859 ce->__unset = fe; 3860 } else if (!strncmp(mname, ZEND_ISSET_FUNC_NAME, mname_len)) { 3861 ce->__isset = fe; 3862 } else if (!strncmp(mname, ZEND_CALLSTATIC_FUNC_NAME, mname_len)) { 3863 ce->__callstatic = fe; 3864 } else if (!strncmp(mname, ZEND_TOSTRING_FUNC_NAME, mname_len)) { 3865 ce->__tostring = fe; 3866 } else if (ce->name_length + 1 == mname_len) { 3867 char *lowercase_name = emalloc(ce->name_length + 1); 3868 zend_str_tolower_copy(lowercase_name, ce->name, ce->name_length); 3869 lowercase_name = (char*)zend_new_interned_string(lowercase_name, ce->name_length + 1, 1 TSRMLS_CC); 3870 if (!memcmp(mname, lowercase_name, mname_len)) { 3871 if (ce->constructor) { 3872 zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name); 3873 } 3874 ce->constructor = fe; 3875 fe->common.fn_flags |= ZEND_ACC_CTOR; 3876 } 3877 str_efree(lowercase_name); 3878 } 3879} 3880/* }}} */ 3881 3882static void zend_add_trait_method(zend_class_entry *ce, const char *name, const char *arKey, uint nKeyLength, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */ 3883{ 3884 zend_function *existing_fn = NULL; 3885 ulong h = zend_hash_func(arKey, nKeyLength); 3886 3887 if (zend_hash_quick_find(&ce->function_table, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) { 3888 if (existing_fn->common.scope == ce) { 3889 /* members from the current class override trait methods */ 3890 /* use temporary *overriden HashTable to detect hidden conflict */ 3891 if (*overriden) { 3892 if (zend_hash_quick_find(*overriden, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) { 3893 if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) { 3894 /* Make sure the trait method is compatible with previosly declared abstract method */ 3895 if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) { 3896 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", 3897 zend_get_function_declaration(fn TSRMLS_CC), 3898 zend_get_function_declaration(existing_fn TSRMLS_CC)); 3899 } 3900 } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { 3901 /* Make sure the abstract declaration is compatible with previous declaration */ 3902 if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) { 3903 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", 3904 zend_get_function_declaration(fn TSRMLS_CC), 3905 zend_get_function_declaration(existing_fn TSRMLS_CC)); 3906 } 3907 return; 3908 } 3909 } 3910 } else { 3911 ALLOC_HASHTABLE(*overriden); 3912 zend_hash_init_ex(*overriden, 2, NULL, NULL, 0, 0); 3913 } 3914 zend_hash_quick_update(*overriden, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn); 3915 return; 3916 } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) { 3917 /* Make sure the trait method is compatible with previosly declared abstract method */ 3918 if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) { 3919 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", 3920 zend_get_function_declaration(fn TSRMLS_CC), 3921 zend_get_function_declaration(existing_fn TSRMLS_CC)); 3922 } 3923 } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { 3924 /* Make sure the abstract declaration is compatible with previous declaration */ 3925 if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) { 3926 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", 3927 zend_get_function_declaration(fn TSRMLS_CC), 3928 zend_get_function_declaration(existing_fn TSRMLS_CC)); 3929 } 3930 return; 3931 } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { 3932 /* two trais can't define the same non-abstract method */ 3933#if 1 3934 zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s", 3935 name, ce->name); 3936#else /* TODO: better errot message */ 3937 zend_error(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s", 3938 fn->common.scope->name, fn->common.function_name, 3939 ce->name, name, 3940 existing_fn->common.scope->name, existing_fn->common.function_name); 3941#endif 3942 } else { 3943 /* inherited members are overridden by members inserted by traits */ 3944 /* check whether the trait method fullfills the inheritance requirements */ 3945 do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC); 3946 } 3947 } 3948 3949 function_add_ref(fn); 3950 zend_hash_quick_update(&ce->function_table, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn); 3951 zend_add_magic_methods(ce, arKey, nKeyLength, fn TSRMLS_CC); 3952} 3953/* }}} */ 3954 3955static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRMLS_DC) /* {{{ */ 3956{ 3957 if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { 3958 3959 fn->common.scope = ce; 3960 3961 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { 3962 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; 3963 } 3964 if (fn->op_array.static_variables) { 3965 ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS; 3966 } 3967 } 3968 return ZEND_HASH_APPLY_KEEP; 3969} 3970/* }}} */ 3971 3972static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ 3973{ 3974 zend_class_entry *ce; 3975 HashTable **overriden; 3976 zend_trait_alias *alias, **alias_ptr; 3977 HashTable *exclude_table; 3978 char *lcname; 3979 unsigned int fnname_len; 3980 zend_function fn_copy; 3981 void *dummy; 3982 3983 ce = va_arg(args, zend_class_entry*); 3984 overriden = va_arg(args, HashTable**); 3985 exclude_table = va_arg(args, HashTable*); 3986 3987 fnname_len = hash_key->nKeyLength - 1; 3988 3989 /* apply aliases which are qualified with a class name, there should not be any ambiguity */ 3990 if (ce->trait_aliases) { 3991 alias_ptr = ce->trait_aliases; 3992 alias = *alias_ptr; 3993 while (alias) { 3994 /* Scope unset or equal to the function we compare to, and the alias applies to fn */ 3995 if (alias->alias != NULL 3996 && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce) 3997 && alias->trait_method->mname_len == fnname_len 3998 && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, hash_key->arKey, fnname_len) == 0)) { 3999 fn_copy = *fn; 4000 4001 /* if it is 0, no modifieres has been changed */ 4002 if (alias->modifiers) { 4003 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK)); 4004 } 4005 4006 lcname = zend_str_tolower_dup(alias->alias, alias->alias_len); 4007 zend_add_trait_method(ce, alias->alias, lcname, alias->alias_len+1, &fn_copy, overriden TSRMLS_CC); 4008 efree(lcname); 4009 4010 /* Record the trait from which this alias was resolved. */ 4011 if (!alias->trait_method->ce) { 4012 alias->trait_method->ce = fn->common.scope; 4013 } 4014 } 4015 alias_ptr++; 4016 alias = *alias_ptr; 4017 } 4018 } 4019 4020 lcname = hash_key->arKey; 4021 4022 if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) { 4023 /* is not in hashtable, thus, function is not to be excluded */ 4024 fn_copy = *fn; 4025 4026 /* apply aliases which have not alias name, just setting visibility */ 4027 if (ce->trait_aliases) { 4028 alias_ptr = ce->trait_aliases; 4029 alias = *alias_ptr; 4030 while (alias) { 4031 /* Scope unset or equal to the function we compare to, and the alias applies to fn */ 4032 if (alias->alias == NULL && alias->modifiers != 0 4033 && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce) 4034 && (alias->trait_method->mname_len == fnname_len) 4035 && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, lcname, fnname_len) == 0)) { 4036 4037 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK)); 4038 4039 /** Record the trait from which this alias was resolved. */ 4040 if (!alias->trait_method->ce) { 4041 alias->trait_method->ce = fn->common.scope; 4042 } 4043 } 4044 alias_ptr++; 4045 alias = *alias_ptr; 4046 } 4047 } 4048 4049 zend_add_trait_method(ce, fn->common.function_name, lcname, fnname_len+1, &fn_copy, overriden TSRMLS_CC); 4050 } 4051 4052 return ZEND_HASH_APPLY_KEEP; 4053} 4054/* }}} */ 4055 4056static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */ 4057{ 4058 zend_uint i; 4059 4060 if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) { 4061 zend_error(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name); 4062 } 4063 4064 for (i = 0; i < ce->num_traits; i++) { 4065 if (ce->traits[i] == trait) { 4066 return; 4067 } 4068 } 4069 zend_error(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name, ce->name); 4070} 4071/* }}} */ 4072 4073static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */ 4074{ 4075 size_t i, j = 0; 4076 zend_trait_precedence *cur_precedence; 4077 zend_trait_method_reference *cur_method_ref; 4078 char *lcname; 4079 zend_bool method_exists; 4080 4081 /* resolve class references */ 4082 if (ce->trait_precedences) { 4083 i = 0; 4084 while ((cur_precedence = ce->trait_precedences[i])) { 4085 /** Resolve classes for all precedence operations. */ 4086 if (cur_precedence->exclude_from_classes) { 4087 cur_method_ref = cur_precedence->trait_method; 4088 if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, 4089 ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) { 4090 zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name); 4091 } 4092 zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC); 4093 4094 /** Ensure that the prefered method is actually available. */ 4095 lcname = zend_str_tolower_dup(cur_method_ref->method_name, 4096 cur_method_ref->mname_len); 4097 method_exists = zend_hash_exists(&cur_method_ref->ce->function_table, 4098 lcname, 4099 cur_method_ref->mname_len + 1); 4100 efree(lcname); 4101 if (!method_exists) { 4102 zend_error(E_COMPILE_ERROR, 4103 "A precedence rule was defined for %s::%s but this method does not exist", 4104 cur_method_ref->ce->name, 4105 cur_method_ref->method_name); 4106 } 4107 4108 /** With the other traits, we are more permissive. 4109 We do not give errors for those. This allows to be more 4110 defensive in such definitions. 4111 However, we want to make sure that the insteadof declartion 4112 is consistent in itself. 4113 */ 4114 j = 0; 4115 while (cur_precedence->exclude_from_classes[j]) { 4116 char* class_name = (char*)cur_precedence->exclude_from_classes[j]; 4117 zend_uint name_length = strlen(class_name); 4118 4119 if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) { 4120 zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name); 4121 } 4122 zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC); 4123 4124 /* make sure that the trait method is not from a class mentioned in 4125 exclude_from_classes, for consistency */ 4126 if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) { 4127 zend_error(E_COMPILE_ERROR, 4128 "Inconsistent insteadof definition. " 4129 "The method %s is to be used from %s, but %s is also on the exclude list", 4130 cur_method_ref->method_name, 4131 cur_precedence->trait_method->ce->name, 4132 cur_precedence->trait_method->ce->name); 4133 } 4134 4135 efree(class_name); 4136 j++; 4137 } 4138 } 4139 i++; 4140 } 4141 } 4142 4143 if (ce->trait_aliases) { 4144 i = 0; 4145 while (ce->trait_aliases[i]) { 4146 /** For all aliases with an explicit class name, resolve the class now. */ 4147 if (ce->trait_aliases[i]->trait_method->class_name) { 4148 cur_method_ref = ce->trait_aliases[i]->trait_method; 4149 if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) { 4150 zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name); 4151 } 4152 zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC); 4153 4154 /** And, ensure that the referenced method is resolvable, too. */ 4155 lcname = zend_str_tolower_dup(cur_method_ref->method_name, 4156 cur_method_ref->mname_len); 4157 method_exists = zend_hash_exists(&cur_method_ref->ce->function_table, 4158 lcname, cur_method_ref->mname_len + 1); 4159 efree(lcname); 4160 4161 if (!method_exists) { 4162 zend_error(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", cur_method_ref->ce->name, cur_method_ref->method_name); 4163 } 4164 } 4165 i++; 4166 } 4167 } 4168} 4169/* }}} */ 4170 4171static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */ 4172{ 4173 size_t i = 0, j; 4174 4175 if (!precedences) { 4176 return; 4177 } 4178 while (precedences[i]) { 4179 if (precedences[i]->exclude_from_classes) { 4180 j = 0; 4181 while (precedences[i]->exclude_from_classes[j]) { 4182 if (precedences[i]->exclude_from_classes[j] == trait) { 4183 zend_uint lcname_len = precedences[i]->trait_method->mname_len; 4184 char *lcname = zend_str_tolower_dup(precedences[i]->trait_method->method_name, lcname_len); 4185 4186 if (zend_hash_add(exclude_table, lcname, lcname_len, NULL, 0, NULL) == FAILURE) { 4187 efree(lcname); 4188 zend_error(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name, trait->name); 4189 } 4190 efree(lcname); 4191 } 4192 ++j; 4193 } 4194 } 4195 ++i; 4196 } 4197} 4198/* }}} */ 4199 4200static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */ 4201{ 4202 zend_uint i; 4203 HashTable *overriden = NULL; 4204 4205 for (i = 0; i < ce->num_traits; i++) { 4206 if (ce->trait_precedences) { 4207 HashTable exclude_table; 4208 4209 /* TODO: revisit this start size, may be its not optimal */ 4210 zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0); 4211 4212 zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]); 4213 4214 /* copies functions, applies defined aliasing, and excludes unused trait methods */ 4215 zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, &exclude_table); 4216 4217 zend_hash_destroy(&exclude_table); 4218 } else { 4219 zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL); 4220 } 4221 } 4222 4223 zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC); 4224 4225 if (overriden) { 4226 zend_hash_destroy(overriden); 4227 FREE_HASHTABLE(overriden); 4228 } 4229} 4230/* }}} */ 4231 4232static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, const char* prop_name, int prop_name_length, ulong prop_hash, zend_class_entry *coliding_ce) /* {{{ */ 4233{ 4234 size_t i; 4235 4236 if (coliding_ce == ce) { 4237 for (i = 0; i < current_trait; i++) { 4238 if (zend_hash_quick_exists(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash)) { 4239 return ce->traits[i]; 4240 } 4241 } 4242 } 4243 4244 return coliding_ce; 4245} 4246/* }}} */ 4247 4248static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */ 4249{ 4250 size_t i; 4251 zend_property_info *property_info; 4252 zend_property_info *coliding_prop; 4253 zval compare_result; 4254 const char* prop_name; 4255 int prop_name_length; 4256 ulong prop_hash; 4257 const char* class_name_unused; 4258 zend_bool not_compatible; 4259 zval* prop_value; 4260 char* doc_comment; 4261 zend_uint flags; 4262 4263 /* In the following steps the properties are inserted into the property table 4264 * for that, a very strict approach is applied: 4265 * - check for compatibility, if not compatible with any property in class -> fatal 4266 * - if compatible, then strict notice 4267 */ 4268 for (i = 0; i < ce->num_traits; i++) { 4269 for (zend_hash_internal_pointer_reset(&ce->traits[i]->properties_info); 4270 zend_hash_get_current_data(&ce->traits[i]->properties_info, (void *) &property_info) == SUCCESS; 4271 zend_hash_move_forward(&ce->traits[i]->properties_info)) { 4272 /* first get the unmangeld name if necessary, 4273 * then check whether the property is already there 4274 */ 4275 flags = property_info->flags; 4276 if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) { 4277 prop_hash = property_info->h; 4278 prop_name = property_info->name; 4279 prop_name_length = property_info->name_length; 4280 } else { 4281 /* for private and protected we need to unmangle the names */ 4282 zend_unmangle_property_name_ex(property_info->name, property_info->name_length, 4283 &class_name_unused, &prop_name, &prop_name_length); 4284 prop_hash = zend_get_hash_value(prop_name, prop_name_length + 1); 4285 } 4286 4287 /* next: check for conflicts with current class */ 4288 if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) { 4289 if (coliding_prop->flags & ZEND_ACC_SHADOW) { 4290 zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash); 4291 flags |= ZEND_ACC_CHANGED; 4292 } else { 4293 if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC)) 4294 == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) { 4295 /* flags are identical, now the value needs to be checked */ 4296 if (flags & ZEND_ACC_STATIC) { 4297 not_compatible = (FAILURE == compare_function(&compare_result, 4298 ce->default_static_members_table[coliding_prop->offset], 4299 ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC)) 4300 || (Z_LVAL(compare_result) != 0); 4301 } else { 4302 not_compatible = (FAILURE == compare_function(&compare_result, 4303 ce->default_properties_table[coliding_prop->offset], 4304 ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC)) 4305 || (Z_LVAL(compare_result) != 0); 4306 } 4307 } else { 4308 /* the flags are not identical, thus, we assume properties are not compatible */ 4309 not_compatible = 1; 4310 } 4311 4312 if (not_compatible) { 4313 zend_error(E_COMPILE_ERROR, 4314 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed", 4315 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name, 4316 property_info->ce->name, 4317 prop_name, 4318 ce->name); 4319 } else { 4320 zend_error(E_STRICT, 4321 "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed", 4322 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name, 4323 property_info->ce->name, 4324 prop_name, 4325 ce->name); 4326 continue; 4327 } 4328 } 4329 } 4330 4331 /* property not found, so lets add it */ 4332 if (flags & ZEND_ACC_STATIC) { 4333 prop_value = ce->traits[i]->default_static_members_table[property_info->offset]; 4334 } else { 4335 prop_value = ce->traits[i]->default_properties_table[property_info->offset]; 4336 } 4337 Z_ADDREF_P(prop_value); 4338 4339 doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL; 4340 zend_declare_property_ex(ce, prop_name, prop_name_length, 4341 prop_value, flags, 4342 doc_comment, property_info->doc_comment_len TSRMLS_CC); 4343 } 4344 } 4345} 4346/* }}} */ 4347 4348static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */ 4349{ 4350 int i = 0; 4351 zend_trait_alias* cur_alias; 4352 char* lc_method_name; 4353 4354 if (ce->trait_aliases) { 4355 while (ce->trait_aliases[i]) { 4356 cur_alias = ce->trait_aliases[i]; 4357 /** The trait for this alias has not been resolved, this means, this 4358 alias was not applied. Abort with an error. */ 4359 if (!cur_alias->trait_method->ce) { 4360 if (cur_alias->alias) { 4361 /** Plain old inconsistency/typo/bug */ 4362 zend_error(E_COMPILE_ERROR, 4363 "An alias (%s) was defined for method %s(), but this method does not exist", 4364 cur_alias->alias, 4365 cur_alias->trait_method->method_name); 4366 } else { 4367 /** Here are two possible cases: 4368 1) this is an attempt to modifiy the visibility 4369 of a method introduce as part of another alias. 4370 Since that seems to violate the DRY principle, 4371 we check against it and abort. 4372 2) it is just a plain old inconsitency/typo/bug 4373 as in the case where alias is set. */ 4374 4375 lc_method_name = zend_str_tolower_dup(cur_alias->trait_method->method_name, 4376 cur_alias->trait_method->mname_len); 4377 if (zend_hash_exists(&ce->function_table, 4378 lc_method_name, 4379 cur_alias->trait_method->mname_len+1)) { 4380 efree(lc_method_name); 4381 zend_error(E_COMPILE_ERROR, 4382 "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error", 4383 cur_alias->trait_method->method_name); 4384 } else { 4385 efree(lc_method_name); 4386 zend_error(E_COMPILE_ERROR, 4387 "The modifiers of the trait method %s() are changed, but this method does not exist. Error", 4388 cur_alias->trait_method->method_name); 4389 4390 } 4391 } 4392 } 4393 i++; 4394 } 4395 } 4396} 4397/* }}} */ 4398 4399ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */ 4400{ 4401 4402 if (ce->num_traits <= 0) { 4403 return; 4404 } 4405 4406 /* complete initialization of trait strutures in ce */ 4407 zend_traits_init_trait_structures(ce TSRMLS_CC); 4408 4409 /* first care about all methods to be flattened into the class */ 4410 zend_do_traits_method_binding(ce TSRMLS_CC); 4411 4412 /* Aliases which have not been applied indicate typos/bugs. */ 4413 zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC); 4414 4415 /* then flatten the properties into it, to, mostly to notfiy developer about problems */ 4416 zend_do_traits_property_binding(ce TSRMLS_CC); 4417 4418 /* verify that all abstract methods from traits have been implemented */ 4419 zend_verify_abstract_class(ce TSRMLS_CC); 4420 4421 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */ 4422 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { 4423 ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; 4424 } 4425} 4426/* }}} */ 4427 4428ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */ 4429{ 4430 zend_function *function; 4431 zval *op1, *op2; 4432 4433 if (compile_time) { 4434 op1 = &CONSTANT_EX(op_array, opline->op1.constant); 4435 op2 = &CONSTANT_EX(op_array, opline->op2.constant); 4436 } else { 4437 op1 = opline->op1.zv; 4438 op2 = opline->op2.zv; 4439 } 4440 4441 zend_hash_quick_find(function_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void *) &function); 4442 if (zend_hash_quick_add(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), function, sizeof(zend_function), NULL)==FAILURE) { 4443 int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR; 4444 zend_function *old_function; 4445 4446 if (zend_hash_quick_find(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), (void *) &old_function)==SUCCESS 4447 && old_function->type == ZEND_USER_FUNCTION 4448 && old_function->op_array.last > 0) { 4449 zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)", 4450 function->common.function_name, 4451 old_function->op_array.filename, 4452 old_function->op_array.opcodes[0].lineno); 4453 } else { 4454 zend_error(error_level, "Cannot redeclare %s()", function->common.function_name); 4455 } 4456 return FAILURE; 4457 } else { 4458 (*function->op_array.refcount)++; 4459 function->op_array.static_variables = NULL; /* NULL out the unbound function */ 4460 return SUCCESS; 4461 } 4462} 4463/* }}} */ 4464 4465void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */ 4466{ 4467 zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference)); 4468 method_ref->ce = NULL; 4469 4470 /* REM: There should not be a need for copying, 4471 zend_do_begin_class_declaration is also just using that string */ 4472 if (class_name) { 4473 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC); 4474 method_ref->class_name = Z_STRVAL(class_name->u.constant); 4475 method_ref->cname_len = Z_STRLEN(class_name->u.constant); 4476 } else { 4477 method_ref->class_name = NULL; 4478 method_ref->cname_len = 0; 4479 } 4480 4481 method_ref->method_name = Z_STRVAL(method_name->u.constant); 4482 method_ref->mname_len = Z_STRLEN(method_name->u.constant); 4483 4484 result->u.op.ptr = method_ref; 4485 result->op_type = IS_TMP_VAR; 4486} 4487/* }}} */ 4488 4489void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */ 4490{ 4491 zend_class_entry *ce = CG(active_class_entry); 4492 zend_trait_alias *trait_alias; 4493 4494 if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) { 4495 zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier"); 4496 return; 4497 } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_ABSTRACT) { 4498 zend_error(E_COMPILE_ERROR, "Cannot use 'abstract' as method modifier"); 4499 return; 4500 } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_FINAL) { 4501 zend_error(E_COMPILE_ERROR, "Cannot use 'final' as method modifier"); 4502 return; 4503 } 4504 4505 trait_alias = emalloc(sizeof(zend_trait_alias)); 4506 trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr; 4507 trait_alias->modifiers = Z_LVAL(modifiers->u.constant); 4508 if (alias) { 4509 trait_alias->alias = Z_STRVAL(alias->u.constant); 4510 trait_alias->alias_len = Z_STRLEN(alias->u.constant); 4511 } else { 4512 trait_alias->alias = NULL; 4513 } 4514 zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC); 4515} 4516/* }}} */ 4517 4518void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */ 4519{ 4520 zend_class_entry *ce = CG(active_class_entry); 4521 zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence)); 4522 4523 trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr; 4524 trait_precedence->exclude_from_classes = (zend_class_entry**) trait_list->u.op.ptr; 4525 4526 zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC); 4527} 4528/* }}} */ 4529 4530ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */ 4531{ 4532 zend_class_entry *ce, **pce; 4533 zval *op1, *op2; 4534 4535 if (compile_time) { 4536 op1 = &CONSTANT_EX(op_array, opline->op1.constant); 4537 op2 = &CONSTANT_EX(op_array, opline->op2.constant); 4538 } else { 4539 op1 = opline->op1.zv; 4540 op2 = opline->op2.zv; 4541 } 4542 if (zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce)==FAILURE) { 4543 zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1)); 4544 return NULL; 4545 } else { 4546 ce = *pce; 4547 } 4548 ce->refcount++; 4549 if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { 4550 ce->refcount--; 4551 if (!compile_time) { 4552 /* If we're in compile time, in practice, it's quite possible 4553 * that we'll never reach this class declaration at runtime, 4554 * so we shut up about it. This allows the if (!defined('FOO')) { return; } 4555 * approach to work. 4556 */ 4557 zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name); 4558 } 4559 return NULL; 4560 } else { 4561 if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) { 4562 zend_verify_abstract_class(ce TSRMLS_CC); 4563 } 4564 return ce; 4565 } 4566} 4567/* }}} */ 4568 4569ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC) /* {{{ */ 4570{ 4571 zend_class_entry *ce, **pce; 4572 int found_ce; 4573 zval *op1, *op2; 4574 4575 if (compile_time) { 4576 op1 = &CONSTANT_EX(op_array, opline->op1.constant); 4577 op2 = &CONSTANT_EX(op_array, opline->op2.constant); 4578 } else { 4579 op1 = opline->op1.zv; 4580 op2 = opline->op2.zv; 4581 } 4582 4583 found_ce = zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce); 4584 4585 if (found_ce == FAILURE) { 4586 if (!compile_time) { 4587 /* If we're in compile time, in practice, it's quite possible 4588 * that we'll never reach this class declaration at runtime, 4589 * so we shut up about it. This allows the if (!defined('FOO')) { return; } 4590 * approach to work. 4591 */ 4592 zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2)); 4593 } 4594 return NULL; 4595 } else { 4596 ce = *pce; 4597 } 4598 4599 if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) { 4600 zend_error(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name, parent_ce->name); 4601 } else if ((parent_ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { 4602 zend_error(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ce->name, parent_ce->name); 4603 } 4604 4605 zend_do_inheritance(ce, parent_ce TSRMLS_CC); 4606 4607 ce->refcount++; 4608 4609 /* Register the derived class */ 4610 if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), pce, sizeof(zend_class_entry *), NULL)==FAILURE) { 4611 zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name); 4612 } 4613 return ce; 4614} 4615/* }}} */ 4616 4617void zend_do_early_binding(