summaryrefslogtreecommitdiff
path: root/Zend/zend_execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r--Zend/zend_execute.c45
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);