![]() |
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
Patch __CLASS__-in-traits.002.patch for Scripting Engine problem Bug #55214Patch version 2011-07-24 18:28 UTC Return to Bug #55214 | Download this patchThis patch renders other patches obsolete Obsolete patches: Patch Revisions:Developer: gron@php.netIndex: Zend/zend_compile.c =================================================================== --- Zend/zend_compile.c (revision 313649) +++ Zend/zend_compile.c (working copy) @@ -3482,11 +3482,13 @@ /* {{{ 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, char *newname TSRMLS_DC) +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; if (fe->op_array.static_variables) { @@ -3498,24 +3500,34 @@ fe->op_array.static_variables = tmpHash; } + + /* TODO: Verify that this size is a global thing, do not see why but is used + like this elsewhere */ + literals_copy = (zend_literal*)emalloc(CG(context).literals_size * sizeof(zend_literal)); + + for (i = 0; i < fe->op_array.last_literal; 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; - } + 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++) { @@ -3525,6 +3537,16 @@ 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); } + } else { + // if __CLASS__ i.e. T_CLASS_C was used, we need to fix it up here + if (target_ce + && Z_TYPE_P(opcode_copy[i].op1.zv) == IS_NULL + && Z_LVAL_P(opcode_copy[i].op1.zv) == ZEND_ACC_TRAIT) { + INIT_ZVAL(class_name_zv); + ZVAL_STRINGL(&class_name_zv, target_ce->name, target_ce->name_length, 0); + class_name_literal = zend_add_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) { @@ -3532,6 +3554,16 @@ 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); } + } else { + // if __CLASS__ i.e. T_CLASS_C was used, we need to fix it up here + if (target_ce + && Z_TYPE_P(opcode_copy[i].op2.zv) == IS_NULL + && Z_LVAL_P(opcode_copy[i].op2.zv) == ZEND_ACC_TRAIT) { + INIT_ZVAL(class_name_zv); + ZVAL_STRINGL(&class_name_zv, target_ce->name, target_ce->name_length, 0); + class_name_literal = zend_add_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; @@ -3559,14 +3591,6 @@ 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); - /* TODO: check whether there is something similar and whether that is ok */ - literals_copy = (zend_literal*)emalloc(fe->op_array.last_literal * sizeof(zend_literal)); - - for (i = 0; i < fe->op_array.last_literal; i++) { - literals_copy[i] = fe->op_array.literals[i]; - zval_copy_ctor(&literals_copy[i].constant); - } - fe->op_array.literals = literals_copy; } /* }}}} */ @@ -3619,7 +3643,7 @@ ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS; } fn_copy = *fn; - zend_traits_duplicate_function(&fn_copy, estrdup(fn->common.function_name) TSRMLS_CC); + zend_traits_duplicate_function(&fn_copy, ce, estrdup(fn->common.function_name) TSRMLS_CC); 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); @@ -3641,6 +3665,7 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { HashTable* target; + zend_class_entry *target_ce; zend_trait_alias** aliases; HashTable* exclude_table; char* lcname; @@ -3648,8 +3673,10 @@ zend_function fn_copy; void* dummy; size_t i = 0; - target = va_arg(args, HashTable*); - aliases = va_arg(args, zend_trait_alias**); + + target = va_arg(args, HashTable*); + target_ce = va_arg(args, zend_class_entry*); + aliases = va_arg(args, zend_trait_alias**); exclude_table = va_arg(args, HashTable*); fnname_len = strlen(fn->common.function_name); @@ -3663,7 +3690,7 @@ && 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, estrndup(aliases[i]->alias, aliases[i]->alias_len) TSRMLS_CC); + zend_traits_duplicate_function(&fn_copy, NULL, estrndup(aliases[i]->alias, aliases[i]->alias_len) TSRMLS_CC); /* if it is 0, no modifieres has been changed */ if (aliases[i]->modifiers) { @@ -3690,7 +3717,7 @@ 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, estrndup(fn->common.function_name, fnname_len) TSRMLS_CC); + zend_traits_duplicate_function(&fn_copy, NULL, estrndup(fn->common.function_name, fnname_len) TSRMLS_CC); /* apply aliases which are not qualified by a class name, or which have not * alias name, just setting visibility */ @@ -3725,9 +3752,9 @@ /* }}} */ /* Copies function table entries to target function table with applied aliasing */ -static void zend_traits_copy_trait_function_table(HashTable *target, HashTable *source, zend_trait_alias** aliases, HashTable* exclude_table TSRMLS_DC) /* {{{ */ +static void zend_traits_copy_trait_function_table(HashTable *target, zend_class_entry *target_ce, HashTable *source, zend_trait_alias** aliases, HashTable* exclude_table TSRMLS_DC) /* {{{ */ { - zend_hash_apply_with_arguments(source TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, target, aliases, exclude_table); + zend_hash_apply_with_arguments(source TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 4, target, target_ce, aliases, exclude_table); } /* }}} */ @@ -3825,10 +3852,10 @@ zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]); /* copies functions, applies defined aliasing, and excludes unused trait methods */ - zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table TSRMLS_CC); + zend_traits_copy_trait_function_table(function_tables[i], ce, &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table TSRMLS_CC); zend_hash_graceful_destroy(&exclude_table); } else { - zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, NULL TSRMLS_CC); + zend_traits_copy_trait_function_table(function_tables[i], ce, &ce->traits[i]->function_table, ce->trait_aliases, NULL TSRMLS_CC); } } Index: Zend/zend_language_scanner.l =================================================================== --- Zend/zend_language_scanner.l (revision 313649) +++ Zend/zend_language_scanner.l (working copy) @@ -1529,16 +1529,25 @@ <ST_IN_SCRIPTING>"__CLASS__" { char *class_name = NULL; - if (CG(active_class_entry)) { - class_name = CG(active_class_entry)->name; - } + if (ZEND_ACC_TRAIT == (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT)) { + // This is a hack, we abuse IS_NULL to indicate an invalid value + // if __CLASS__ is encountered in a trait, however, we also not that we + // should fix it up when we copy the method into an actual class + zendlval->value.lval = ZEND_ACC_TRAIT; + zendlval->type = IS_NULL; + } else { + if (CG(active_class_entry)) { + class_name = CG(active_class_entry)->name; + } - if (!class_name) { - class_name = ""; + if (!class_name) { + class_name = ""; + } + + zendlval->value.str.len = strlen(class_name); + zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len); + zendlval->type = IS_STRING; } - zendlval->value.str.len = strlen(class_name); - zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len); - zendlval->type = IS_STRING; return T_CLASS_C; } |
![]() All rights reserved. |
Last updated: Thu Mar 13 17:01:30 2025 UTC |