summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/bug29368_3.phpt33
-rw-r--r--Zend/zend_compile.c4
-rw-r--r--Zend/zend_compile.h4
-rw-r--r--Zend/zend_execute.c12
-rw-r--r--Zend/zend_opcode.c8
-rw-r--r--Zend/zend_vm_def.h36
-rw-r--r--Zend/zend_vm_execute.h74
-rw-r--r--ext/opcache/Optimizer/zend_dump.c6
-rw-r--r--ext/opcache/tests/opt/dce_006.phpt2
9 files changed, 69 insertions, 110 deletions
diff --git a/Zend/tests/bug29368_3.phpt b/Zend/tests/bug29368_3.phpt
new file mode 100644
index 0000000000..fafcc2a0ef
--- /dev/null
+++ b/Zend/tests/bug29368_3.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Bug #29368.3 (The destructor is called when an exception is thrown from the constructor).
+--FILE--
+<?php
+class Foo {
+ function __construct() {
+ echo __METHOD__ . "\n";
+ }
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+class Bar {
+ function __construct() {
+ echo __METHOD__ . "\n";
+ throw new Exception;
+ }
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+try {
+ new Foo() + new Bar();
+} catch(Exception $exc) {
+ echo "Caught exception!\n";
+}
+?>
+--EXPECT--
+Foo::__construct
+Bar::__construct
+Foo::__destruct
+Caught exception!
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index ccdbd8a1b7..1294c1f488 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -3066,7 +3066,6 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *
zend_op *opline;
uint32_t opnum_init = get_next_op_number() - 1;
uint32_t arg_count;
- uint32_t call_flags;
arg_count = zend_compile_args(args_ast, fbc);
@@ -3079,10 +3078,7 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *
opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc);
}
- call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0);
opline = zend_emit_op(result, zend_get_call_op(opline, fbc), NULL, NULL);
- opline->op1.num = call_flags;
-
zend_do_extended_fcall_end();
}
/* }}} */
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 82d70fd4b0..523d04e794 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -172,7 +172,8 @@ typedef struct _zend_try_catch_element {
#define ZEND_LIVE_LOOP 1
#define ZEND_LIVE_SILENCE 2
#define ZEND_LIVE_ROPE 3
-#define ZEND_LIVE_MASK 3
+#define ZEND_LIVE_NEW 4
+#define ZEND_LIVE_MASK 7
typedef struct _zend_live_range {
uint32_t var; /* low bits are used for variable type (ZEND_LIVE_* macros) */
@@ -506,7 +507,6 @@ struct _zend_execute_data {
#define ZEND_CALL_NESTED (0 << 1)
#define ZEND_CALL_TOP (1 << 1)
#define ZEND_CALL_FREE_EXTRA_ARGS (1 << 2)
-#define ZEND_CALL_CTOR (1 << 3)
#define ZEND_CALL_HAS_SYMBOL_TABLE (1 << 4)
#define ZEND_CALL_CLOSURE (1 << 5)
#define ZEND_CALL_RELEASE_THIS (1 << 6)
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index bb3ca87b04..6d13457a43 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -3675,12 +3675,6 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
zend_vm_stack_free_args(EX(call));
if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
- if (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR) {
- GC_DELREF(Z_OBJ(call->This));
- if (GC_REFCOUNT(Z_OBJ(call->This)) == 1) {
- zend_object_store_ctor_failed(Z_OBJ(call->This));
- }
- }
OBJ_RELEASE(Z_OBJ(call->This));
}
if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) {
@@ -3729,6 +3723,12 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num,
if (kind == ZEND_LIVE_TMPVAR) {
zval_ptr_dtor_nogc(var);
+ } else if (kind == ZEND_LIVE_NEW) {
+ zend_object *obj;
+ ZEND_ASSERT(Z_TYPE_P(var) == IS_OBJECT);
+ obj = Z_OBJ_P(var);
+ zend_object_store_ctor_failed(obj);
+ OBJ_RELEASE(obj);
} else if (kind == ZEND_LIVE_LOOP) {
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
zend_hash_iterator_del(Z_FE_ITER_P(var));
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 5b1914c99d..a44a7c562d 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -603,10 +603,15 @@ static void emit_live_range(
start++;
break;
/* Objects created via ZEND_NEW are only fully initialized
- * after the DO_FCALL (constructor call). */
+ * after the DO_FCALL (constructor call).
+ * We are creating two live-ranges: ZEND_LINE_NEW for uninitialized
+ * part, and ZEND_LIVE_TMPVAR for initialized.
+ */
case ZEND_NEW:
{
int level = 0;
+ uint32_t orig_start = start;
+
while (def_opline + 1 < use_opline) {
def_opline++;
start++;
@@ -635,6 +640,7 @@ static void emit_live_range(
}
}
}
+ emit_live_range_raw(op_array, var_num, ZEND_LIVE_NEW, orig_start + 1, start + 1);
if (start + 1 == end) {
/* Trivial live-range, no need to store it. */
return;
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index d71694223f..e975a92014 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2740,16 +2740,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY)
EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
- zend_object *object = Z_OBJ(execute_data->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(execute_data->This));
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
}
@@ -2771,16 +2762,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY)
}
EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
- zend_object *object = Z_OBJ(execute_data->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(execute_data->This));
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
}
@@ -3985,7 +3967,6 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
USE_OPLINE
zend_execute_data *call = EX(call);
zend_function *fbc = call->func;
- zend_object *object;
zval *ret;
SAVE_OPLINE();
@@ -4079,16 +4060,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
ZEND_VM_C_LABEL(fcall_end):
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
- object = Z_OBJ(call->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(call->This));
}
zend_vm_stack_free_call_frame(call);
@@ -5322,7 +5294,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N
}
/* We are not handling overloaded classes right now */
call = zend_vm_stack_push_call_frame(
- ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR,
+ ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS,
constructor,
opline->extended_value,
ce,
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 7977a2a4a0..ad4f978ad1 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -796,16 +796,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
- zend_object *object = Z_OBJ(execute_data->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(execute_data->This));
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
}
@@ -827,16 +818,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
}
EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
- zend_object *object = Z_OBJ(execute_data->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(execute_data->This));
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
}
@@ -1207,7 +1189,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
USE_OPLINE
zend_execute_data *call = EX(call);
zend_function *fbc = call->func;
- zend_object *object;
zval *ret;
SAVE_OPLINE();
@@ -1301,16 +1282,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
fcall_end:
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
- object = Z_OBJ(call->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(call->This));
}
zend_vm_stack_free_call_frame(call);
@@ -1328,7 +1300,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
USE_OPLINE
zend_execute_data *call = EX(call);
zend_function *fbc = call->func;
- zend_object *object;
zval *ret;
SAVE_OPLINE();
@@ -1422,16 +1393,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
fcall_end:
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
- object = Z_OBJ(call->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(call->This));
}
zend_vm_stack_free_call_frame(call);
@@ -9122,7 +9084,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_UNUSED_HANDLER(
}
/* We are not handling overloaded classes right now */
call = zend_vm_stack_push_call_frame(
- ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR,
+ ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS,
constructor,
opline->extended_value,
ce,
@@ -29170,7 +29132,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_UNUSED_HANDLER(ZE
}
/* We are not handling overloaded classes right now */
call = zend_vm_stack_push_call_frame(
- ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR,
+ ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS,
constructor,
opline->extended_value,
ce,
@@ -36681,7 +36643,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_UNUSED_UNUSED_HANDLER
}
/* We are not handling overloaded classes right now */
call = zend_vm_stack_push_call_frame(
- ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR,
+ ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS,
constructor,
opline->extended_value,
ce,
@@ -59189,16 +59151,7 @@ zend_leave_helper_SPEC_LABEL:
EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
- zend_object *object = Z_OBJ(execute_data->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(execute_data->This));
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
}
@@ -59220,16 +59173,7 @@ zend_leave_helper_SPEC_LABEL:
}
EG(current_execute_data) = EX(prev_execute_data);
if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
- zend_object *object = Z_OBJ(execute_data->This);
-#if 0
- if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
-#else
- if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
-#endif
- GC_DELREF(object);
- zend_object_store_ctor_failed(object);
- }
- OBJ_RELEASE(object);
+ OBJ_RELEASE(Z_OBJ(execute_data->This));
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
}
diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c
index 3bc0650ab4..01c907cfea 100644
--- a/ext/opcache/Optimizer/zend_dump.c
+++ b/ext/opcache/Optimizer/zend_dump.c
@@ -1027,6 +1027,9 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons
case ZEND_LIVE_ROPE:
fprintf(stderr, "(rope)\n");
break;
+ case ZEND_LIVE_NEW:
+ fprintf(stderr, "(new)\n");
+ break;
}
}
}
@@ -1083,6 +1086,9 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons
case ZEND_LIVE_ROPE:
fprintf(stderr, "(rope)\n");
break;
+ case ZEND_LIVE_NEW:
+ fprintf(stderr, "(new)\n");
+ break;
}
}
}
diff --git a/ext/opcache/tests/opt/dce_006.phpt b/ext/opcache/tests/opt/dce_006.phpt
index b53a73e990..c84805247a 100644
--- a/ext/opcache/tests/opt/dce_006.phpt
+++ b/ext/opcache/tests/opt/dce_006.phpt
@@ -33,6 +33,8 @@ L3 (6): CV1($a) = QM_ASSIGN V2
L4 (7): ASSIGN_OBJ CV1($a) string("foo")
L5 (7): OP_DATA CV0($x)
L6 (8): RETURN null
+LIVE RANGES:
+ 2: L2 - L3 (new)
A::__destruct: ; (lines=1, args=0, vars=0, tmps=0)
; (after optimizer)