}
/* }}} */
-/* {{{ Originates from php_runkit_function_copy_ctor
- Duplicate structures in an op_array where necessary to make an outright duplicate */
-static void zend_traits_duplicate_function(zend_function *fe, zend_class_entry *target_ce, char *newname TSRMLS_DC)
-{
- zend_literal *literals_copy;
- zend_compiled_variable *dupvars;
- zend_op *opcode_copy;
- zval class_name_zv;
- int class_name_literal;
- int i;
- int number_of_literals;
-
- if (fe->op_array.static_variables) {
- HashTable *tmpHash;
-
- ALLOC_HASHTABLE(tmpHash);
- zend_hash_init(tmpHash, zend_hash_num_elements(fe->op_array.static_variables), NULL, ZVAL_PTR_DTOR, 0);
- zend_hash_apply_with_arguments(fe->op_array.static_variables TSRMLS_CC, (apply_func_args_t)zval_copy_static_var, 1, tmpHash);
-
- fe->op_array.static_variables = tmpHash;
- }
-
- number_of_literals = fe->op_array.last_literal;
- literals_copy = (zend_literal*)emalloc(number_of_literals * sizeof(zend_literal));
-
- for (i = 0; i < number_of_literals; i++) {
- literals_copy[i] = fe->op_array.literals[i];
- zval_copy_ctor(&literals_copy[i].constant);
- }
- fe->op_array.literals = literals_copy;
-
-
- fe->op_array.refcount = emalloc(sizeof(zend_uint));
- *(fe->op_array.refcount) = 1;
-
- if (fe->op_array.vars) {
- i = fe->op_array.last_var;
- dupvars = safe_emalloc(fe->op_array.last_var, sizeof(zend_compiled_variable), 0);
- while (i > 0) {
- i--;
- dupvars[i].name = estrndup(fe->op_array.vars[i].name, fe->op_array.vars[i].name_len);
- dupvars[i].name_len = fe->op_array.vars[i].name_len;
- dupvars[i].hash_value = fe->op_array.vars[i].hash_value;
- }
- fe->op_array.vars = dupvars;
- } else {
- fe->op_array.vars = NULL;
- }
-
- opcode_copy = safe_emalloc(sizeof(zend_op), fe->op_array.last, 0);
- for(i = 0; i < fe->op_array.last; i++) {
- opcode_copy[i] = fe->op_array.opcodes[i];
- if (opcode_copy[i].op1_type != IS_CONST) {
- switch (opcode_copy[i].opcode) {
- case ZEND_GOTO:
- case ZEND_JMP:
- if (opcode_copy[i].op1.jmp_addr && opcode_copy[i].op1.jmp_addr >= fe->op_array.opcodes &&
- opcode_copy[i].op1.jmp_addr < fe->op_array.opcodes + fe->op_array.last) {
- opcode_copy[i].op1.jmp_addr = opcode_copy + (fe->op_array.opcodes[i].op1.jmp_addr - fe->op_array.opcodes);
- }
- break;
- }
- } else {
- /* if __CLASS__ i.e. T_CLASS_C was used, we need to fix it up here */
- if (target_ce
- /* REM: used a IS_NULL place holder with a special marker LVAL */
- && Z_TYPE_P(opcode_copy[i].op1.zv) == IS_NULL
- && Z_LVAL_P(opcode_copy[i].op1.zv) == ZEND_ACC_TRAIT
- /* Only on merge into an actual class */
- && (ZEND_ACC_TRAIT != (target_ce->ce_flags & ZEND_ACC_TRAIT)))
- {
- INIT_ZVAL(class_name_zv);
- ZVAL_STRINGL(&class_name_zv, target_ce->name, target_ce->name_length, 1);
- class_name_literal = zend_append_individual_literal(&fe->op_array, &class_name_zv TSRMLS_CC);
- opcode_copy[i].op1.zv = &fe->op_array.literals[class_name_literal].constant;
- }
- }
-
- if (opcode_copy[i].op2_type != IS_CONST) {
- switch (opcode_copy[i].opcode) {
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_JMP_SET_VAR:
- if (opcode_copy[i].op2.jmp_addr && opcode_copy[i].op2.jmp_addr >= fe->op_array.opcodes &&
- opcode_copy[i].op2.jmp_addr < fe->op_array.opcodes + fe->op_array.last) {
- opcode_copy[i].op2.jmp_addr = opcode_copy + (fe->op_array.opcodes[i].op2.jmp_addr - fe->op_array.opcodes);
- }
- break;
- }
- } else {
- /* if __CLASS__ i.e. T_CLASS_C was used, we need to fix it up here */
- if (target_ce
- /* REM: used a IS_NULL place holder with a special marker LVAL */
- && Z_TYPE_P(opcode_copy[i].op2.zv) == IS_NULL
- && Z_LVAL_P(opcode_copy[i].op2.zv) == ZEND_ACC_TRAIT
- /* Only on merge into an actual class */
- && (ZEND_ACC_TRAIT != (target_ce->ce_flags & ZEND_ACC_TRAIT)))
- {
- INIT_ZVAL(class_name_zv);
- ZVAL_STRINGL(&class_name_zv, target_ce->name, target_ce->name_length, 1);
- class_name_literal = zend_append_individual_literal(&fe->op_array, &class_name_zv TSRMLS_CC);
- opcode_copy[i].op2.zv = &fe->op_array.literals[class_name_literal].constant;
- }
- }
- }
- fe->op_array.opcodes = opcode_copy;
- fe->op_array.function_name = newname;
-
- /* was setting it to fe which does not work since fe is stack allocated and not a stable address */
- /* fe->op_array.prototype = fe->op_array.prototype; */
- if (fe->op_array.arg_info) {
- zend_arg_info *tmpArginfo;
-
- tmpArginfo = safe_emalloc(sizeof(zend_arg_info), fe->op_array.num_args, 0);
- for(i = 0; i < fe->op_array.num_args; i++) {
- tmpArginfo[i] = fe->op_array.arg_info[i];
-
- tmpArginfo[i].name = estrndup(tmpArginfo[i].name, tmpArginfo[i].name_len);
- if (tmpArginfo[i].class_name) {
- tmpArginfo[i].class_name = estrndup(tmpArginfo[i].class_name, tmpArginfo[i].class_name_len);
- }
- }
- fe->op_array.arg_info = tmpArginfo;
- }
-
- fe->op_array.doc_comment = estrndup(fe->op_array.doc_comment, fe->op_array.doc_comment_len);
- fe->op_array.try_catch_array = (zend_try_catch_element*)estrndup((char*)fe->op_array.try_catch_array, sizeof(zend_try_catch_element) * fe->op_array.last_try_catch);
-
- fe->op_array.brk_cont_array = (zend_brk_cont_element*)estrndup((char*)fe->op_array.brk_cont_array, sizeof(zend_brk_cont_element) * fe->op_array.last_brk_cont);
-
-}
-/* }}} */
-
static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint mname_len, zend_function* fe TSRMLS_DC) /* {{{ */
{
if (!strncmp(mname, ZEND_CLONE_FUNC_NAME, mname_len)) {
ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
}
fn_copy = *fn;
- zend_traits_duplicate_function(&fn_copy, ce, estrdup(fn->common.function_name) TSRMLS_CC);
+ function_add_ref(&fn_copy);
if (zend_hash_quick_update(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, &fn_copy, sizeof(zend_function), (void**)&fn_copy_p)==FAILURE) {
zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occured during updating class method table", hash_key->arKey);
&& aliases[i]->trait_method->mname_len == fnname_len
&& (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
fn_copy = *fn;
- zend_traits_duplicate_function(&fn_copy, NULL, estrndup(aliases[i]->alias, aliases[i]->alias_len) TSRMLS_CC);
+ function_add_ref(&fn_copy);
+ /* this function_name is never destroyed, because its refcount
+ greater than 1, classes are always destoyed in reverse order
+ and trait is declared early than this class */
+ fn_copy.common.function_name = aliases[i]->alias;
/* if it is 0, no modifieres has been changed */
if (aliases[i]->modifiers) {
if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {
/* is not in hashtable, thus, function is not to be excluded */
fn_copy = *fn;
- zend_traits_duplicate_function(&fn_copy, NULL, estrndup(fn->common.function_name, fnname_len) TSRMLS_CC);
+ function_add_ref(&fn_copy);
/* apply aliases which are not qualified by a class name, or which have not
* alias name, just setting visibility */
zend_register_stringl_constant(name, name_len, strval, strlen(strval), flags, module_number TSRMLS_CC);
}
-static int zend_get_halt_offset_constant(const char *name, uint name_len, zend_constant **c TSRMLS_DC)
+static int zend_get_special_constant(const char *name, uint name_len, zend_constant **c TSRMLS_DC)
{
int ret;
static char haltoff[] = "__COMPILER_HALT_OFFSET__";
if (!EG(in_execution)) {
return 0;
+ } else if (name_len == sizeof("__CLASS__")-1 &&
+ !memcmp(name, "__CLASS__", sizeof("__CLASS__")-1)) {
+ zend_constant tmp;
+
+ /* Returned constants may be cached, so they have to be stored */
+ if (EG(scope) && EG(scope)->name) {
+ int const_name_len;
+ char *const_name;
+ ALLOCA_FLAG(use_heap)
+
+ const_name_len = sizeof("\0__CLASS__") + EG(scope)->name_length;
+ const_name = do_alloca(const_name_len, use_heap);
+ memcpy(const_name, "\0__CLASS__", sizeof("\0__CLASS__")-1);
+ zend_str_tolower_copy(const_name + sizeof("\0__CLASS__")-1, EG(scope)->name, EG(scope)->name_length);
+ if (zend_hash_find(EG(zend_constants), const_name, const_name_len, (void**)c) == FAILURE) {
+ zend_hash_add(EG(zend_constants), const_name, const_name_len, (void*)&tmp, sizeof(zend_constant), (void**)c);
+ memset(*c, 0, sizeof(zend_constant));
+ Z_STRVAL((**c).value) = estrndup(EG(scope)->name, EG(scope)->name_length);
+ Z_STRLEN((**c).value) = EG(scope)->name_length;
+ Z_TYPE((**c).value) = IS_STRING;
+ }
+ free_alloca(const_name, use_heap);
+ } else {
+ if (zend_hash_find(EG(zend_constants), "\0__CLASS__", sizeof("\0__CLASS__"), (void**)c) == FAILURE) {
+ zend_hash_add(EG(zend_constants), "\0__CLASS__", sizeof("\0__CLASS__"), (void*)&tmp, sizeof(zend_constant), (void**)c);
+ memset(*c, 0, sizeof(zend_constant));
+ Z_STRVAL((**c).value) = estrndup("", 0);
+ Z_STRLEN((**c).value) = 0;
+ Z_TYPE((**c).value) = IS_STRING;
+ }
+ }
+ return 1;
} else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 &&
!memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
const char *cfilename;
retval=0;
}
} else {
- retval = zend_get_halt_offset_constant(name, name_len, &c TSRMLS_CC);
+ retval = zend_get_special_constant(name, name_len, &c TSRMLS_CC);
}
efree(lookup_name);
}
(c->flags & CONST_CS) != 0) {
key--;
- if (!zend_get_halt_offset_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+ if (!zend_get_special_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
return NULL;
}
}
}
} else {
key--;
- if (!zend_get_halt_offset_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+ if (!zend_get_special_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
return NULL;
}
}