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