diff options
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r-- | Zend/zend_execute.c | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index ca8a7303bc..dc605f5fff 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1592,14 +1592,45 @@ send_by_ref: continue; } break; - case ZEND_CASE: - if (opline->op1.op_type == IS_VAR) { - PZVAL_LOCK(*Ts[opline->op1.u.var].var); + case ZEND_CASE: { + int switch_expr_is_overloaded=0; + + if (opline->op1.op_type==IS_VAR) { + if (Ts[opline->op1.u.var].var) { + PZVAL_LOCK(*Ts[opline->op1.u.var].var); + } else { + switch_expr_is_overloaded = 1; + if (Ts[opline->op1.u.var].EA.type==IS_STRING_OFFSET) { + Ts[opline->op1.u.var].EA.str->refcount++; + } + } + } + is_equal_function(&Ts[opline->result.u.var].tmp_var, + get_zval_ptr(&opline->op1, Ts, &free_op1, BP_VAR_R), + get_zval_ptr(&opline->op2, Ts, &free_op2, BP_VAR_R)); + + FREE_OP(&opline->op2, free_op2); + if (switch_expr_is_overloaded) { + /* We only free op1 if this is a string offset, + * Since if it is a TMP_VAR, it'll be reused by + * other CASE opcodes (whereas string offsets + * are allocated at each get_zval_ptr()) + */ + FREE_OP(&opline->op1, free_op1); + Ts[opline->op1.u.var].var = NULL; + } + } + break; + case ZEND_SWITCH_FREE: + switch (opline->op1.op_type) { + case IS_VAR: + get_zval_ptr(&opline->op1, Ts, &free_op1, BP_VAR_R); + FREE_OP(&opline->op1, free_op1); + break; + case IS_TMP_VAR: + zendi_zval_dtor(Ts[opline->op1.u.var].tmp_var); + break; } - is_equal_function(&Ts[opline->result.u.var].tmp_var, - get_zval_ptr(&opline->op1, Ts, &free_op1, BP_VAR_R), - get_zval_ptr(&opline->op2, Ts, &free_op2, BP_VAR_R) ); - FREE_OP(&opline->op2, free_op2); break; case ZEND_NEW: { zval *tmp = get_zval_ptr(&opline->op1, Ts, &free_op1, BP_VAR_R); |