From: Andi Gutmans Date: Mon, 4 Feb 2002 19:29:56 +0000 (+0000) Subject: - Fix problem with the objects_destructor called during shutdown. It was X-Git-Tag: BEFORE_NEW_OBJECT_MODEL~2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e366f5dbd8a6a56966e07443f0b59eb7d818f037;p=php - Fix problem with the objects_destructor called during shutdown. It was - freeing objects from id 0 instead of id 1. id 0 is not used. - Change isset/empty opcodes to support static members and the new way of - doing $this->foobar. Also the opcodes operate now on the hash table - combined with the variable names so that they can be overloaded by the - soon to be added overloading patch. --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0132bb9ab0..ba164c8969 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2420,20 +2420,29 @@ void zend_do_unset(znode *variable, int type TSRMLS_DC) void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC) { - zend_op *opline; + zend_op *last_op; zend_do_end_variable_parse(BP_VAR_IS, 0 TSRMLS_CC); - zend_check_writable_variable(variable); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); + /* Check what to do with this later on when adding all of the check writable stuff + * zend_check_writable_variable(variable); + */ - opline->opcode = ZEND_ISSET_ISEMPTY; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *variable; - opline->op2.u.constant.value.lval = type; - SET_UNUSED(opline->op2); - *result = opline->result; + last_op = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array))-1]; + + switch (last_op->opcode) { + case ZEND_FETCH_IS: + last_op->opcode = ZEND_ISSET_ISEMPTY_VAR; + break; + case ZEND_FETCH_DIM_IS: + case ZEND_FETCH_OBJ_IS: + last_op->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ; + break; + } + last_op->result.op_type = IS_TMP_VAR; + last_op->extended_value = type; + + *result = last_op->result; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 6dfa738d58..f1eb9d0e53 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -491,7 +491,6 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_UNSET_VAR 74 #define ZEND_UNSET_DIM_OBJ 75 -#define ZEND_ISSET_ISEMPTY 76 #define ZEND_FE_RESET 77 #define ZEND_FE_FETCH 78 @@ -547,6 +546,9 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_INIT_METHOD_CALL 113 #define ZEND_INIT_STATIC_METHOD_CALL 114 +#define ZEND_ISSET_ISEMPTY_VAR 115 +#define ZEND_ISSET_ISEMPTY_DIM_OBJ 116 + /* end of block */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 9f5dbbf898..5fc60237db 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -521,40 +521,35 @@ static void print_refcount(zval *p, char *str) print_refcount(NULL, NULL); } - -static void zend_fetch_var_address(zend_op *opline, temp_variable *Ts, int type TSRMLS_DC) +static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_variable *Ts, int type TSRMLS_DC) { - int free_op1; - zval *varname = get_zval_ptr(&opline->op1, Ts, &free_op1, BP_VAR_R); - zval **retval; - zval tmp_varname; - HashTable *target_symbol_table=0; - switch (opline->op2.u.EA.type) { case ZEND_FETCH_LOCAL: - target_symbol_table = EG(active_symbol_table); + return EG(active_symbol_table); break; case ZEND_FETCH_GLOBAL: +/* Don't think this is actually needed. if (opline->op1.op_type == IS_VAR) { PZVAL_LOCK(varname); } - target_symbol_table = &EG(symbol_table); +*/ + return &EG(symbol_table); break; case ZEND_FETCH_STATIC: if (!EG(active_op_array)->static_variables) { ALLOC_HASHTABLE(EG(active_op_array)->static_variables); zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); } - target_symbol_table = EG(active_op_array)->static_variables; + return EG(active_op_array)->static_variables; break; case ZEND_FETCH_STATIC_MEMBER: - target_symbol_table = Ts[opline->op2.u.var].EA.class_entry->static_members; + return Ts[opline->op2.u.var].EA.class_entry->static_members; break; case ZEND_FETCH_FROM_THIS: if (!EG(this)) { zend_error(E_ERROR, "Using $this when not in object context"); } - target_symbol_table = Z_OBJPROP_P(EG(this)); + return Z_OBJPROP_P(EG(this)); break; case ZEND_FETCH_THIS: { @@ -569,11 +564,26 @@ static void zend_fetch_var_address(zend_op *opline, temp_variable *Ts, int type Ts[opline->result.u.var].var.ptr_ptr = &EG(this); SELECTIVE_PZVAL_LOCK(EG(this), &opline->result); AI_USE_PTR(Ts[opline->result.u.var].var); - return; + return NULL; break; } EMPTY_SWITCH_DEFAULT_CASE() } +} + + +static void zend_fetch_var_address(zend_op *opline, temp_variable *Ts, int type TSRMLS_DC) +{ + int free_op1; + zval *varname = get_zval_ptr(&opline->op1, Ts, &free_op1, BP_VAR_R); + zval **retval; + zval tmp_varname; + HashTable *target_symbol_table; + + target_symbol_table = zend_get_target_symbol_table(opline, Ts, type TSRMLS_CC); + if (!target_symbol_table) { + return; + } if (varname->type != IS_STRING) { tmp_varname = *varname; @@ -581,6 +591,7 @@ static void zend_fetch_var_address(zend_op *opline, temp_variable *Ts, int type convert_to_string(&tmp_varname); varname = &tmp_varname; } + if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: @@ -2484,7 +2495,8 @@ send_by_ref: EG(return_value_ptr_ptr) = original_return_value; } NEXT_OPCODE(); - case ZEND_UNSET_VAR: { + case ZEND_UNSET_VAR: + { zval tmp, *variable = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R); zval **object; zend_bool unset_object; @@ -2701,54 +2713,133 @@ send_by_ref: } } NEXT_OPCODE(); - case ZEND_ISSET_ISEMPTY: { - zval **var = get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), BP_VAR_IS); - zval *value; - int isset; - - if (!var) { - if (EX(Ts)[EX(opline)->op1.u.var].EA.type == IS_STRING_OFFSET) { - PZVAL_LOCK(EX(Ts)[EX(opline)->op1.u.var].EA.data.str_offset.str); - value = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_IS); - if (value->value.str.val == empty_string) { - isset = 0; + case ZEND_ISSET_ISEMPTY_VAR: + { + zval tmp, *variable = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R); + zval **value; + zend_bool isset = 1; + HashTable *target_symbol_table; + + target_symbol_table = zend_get_target_symbol_table(EX(opline), EX(Ts), BP_VAR_IS TSRMLS_CC); + + if (variable->type != IS_STRING) { + tmp = *variable; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + variable = &tmp; + } + + if (zend_hash_find(target_symbol_table, variable->value.str.val, variable->value.str.len+1, (void **) &value) == FAILURE) { + isset = 0; + } + + EX(Ts)[EX(opline)->result.u.var].tmp_var.type = IS_BOOL; + + switch (EX(opline)->extended_value) { + case ZEND_ISSET: + if (isset && Z_TYPE_PP(value) == IS_NULL) { + EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 0; } else { - isset = 1; + EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = isset; } - } else { /* IS_OVERLOADED_OBJECT */ - value = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_IS); - if (value->type == IS_NULL) { - isset = 0; + break; + case ZEND_ISEMPTY: + if (!isset || !zend_is_true(*value)) { + EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 1; } else { - isset = 1; + EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 0; + } + break; + } + + if (variable == &tmp) { + zval_dtor(&tmp); + } + FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1)); + } + NEXT_OPCODE(); + case ZEND_ISSET_ISEMPTY_DIM_OBJ: + { + zval **container = get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), BP_VAR_R); + zval *offset = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R); + zval **value; + int isset = 1; + + if (container) { + HashTable *ht; + + switch ((*container)->type) { + case IS_ARRAY: + ht = (*container)->value.ht; + break; + case IS_OBJECT: + ht = Z_OBJPROP_PP(container); + break; + default: + ht = NULL; + break; + } + if (ht) { + switch (offset->type) { + case IS_DOUBLE: + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + { + long index; + + if (offset->type == IS_DOUBLE) { + index = (long) offset->value.lval; + } else { + index = offset->value.lval; + } + if (zend_hash_index_find(ht, index, (void **) &value) == FAILURE) { + isset = 0; + } + break; + } + case IS_STRING: + if (zend_hash_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == FAILURE) { + isset = 0; + } + break; + case IS_NULL: + if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == FAILURE) { + isset = 0; + } + break; + default: + zend_error(E_WARNING, "Illegal offset type in unset"); + break; } } - } else if (*var==EG(uninitialized_zval_ptr) || ((*var)->type == IS_NULL)) { - value = *var; - isset = 0; } else { - value = *var; - isset = 1; + /* overloaded element & string offsets */ } + + EX(Ts)[EX(opline)->result.u.var].tmp_var.type = IS_BOOL; - switch (EX(opline)->op2.u.constant.value.lval) { + switch (EX(opline)->extended_value) { case ZEND_ISSET: - EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = isset; + if (isset && Z_TYPE_PP(value) == IS_NULL) { + EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 0; + } else { + EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = isset; + } break; case ZEND_ISEMPTY: - if (!isset || !zend_is_true(value)) { + if (!isset || !zend_is_true(*value)) { EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 1; } else { EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 0; } break; } - EX(Ts)[EX(opline)->result.u.var].tmp_var.type = IS_BOOL; - if (!var) { - FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1)); - } + + FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2)); } NEXT_OPCODE(); + break; case ZEND_EXIT: if (EX(opline)->op1.op_type != IS_UNUSED) { zval *ptr; diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index bdb77f05d0..ddbbee5f2a 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -72,9 +72,9 @@ static inline void zend_objects_destroy_object(zend_object *object, zend_object_ void zend_objects_call_destructors(zend_objects *objects TSRMLS_DC) { - int i = 1; + zend_uint i = 1; - for (i = 0; i < objects->top ; i++) { + for (i = 1; i < objects->top ; i++) { if (EG(objects).object_buckets[i].valid) { EG(objects).object_buckets[i].constructor_called = 1; zend_objects_destroy_object(&EG(objects).object_buckets[i].bucket.obj.object, i TSRMLS_CC);