diff options
Diffstat (limited to 'Zend')
| -rw-r--r-- | Zend/tests/bug29368_3.phpt | 33 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 4 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 12 | ||||
| -rw-r--r-- | Zend/zend_execute.c | 12 | ||||
| -rw-r--r-- | Zend/zend_opcode.c | 8 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 36 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 74 | 
7 files changed, 65 insertions, 114 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 0b9a50cdb1..83bd649bb9 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3043,7 +3043,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); @@ -3056,10 +3055,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 a882d4f675..3144bc72df 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) */ @@ -501,11 +502,10 @@ struct _zend_execute_data {  #define ZEND_CALL_FREE_EXTRA_ARGS    (1 << 19)  #define ZEND_CALL_HAS_SYMBOL_TABLE   (1 << 20)  #define ZEND_CALL_RELEASE_THIS       (1 << 21) -#define ZEND_CALL_CTOR               (1 << 22) -#define ZEND_CALL_CLOSURE            (1 << 23) -#define ZEND_CALL_FAKE_CLOSURE       (1 << 24) -#define ZEND_CALL_GENERATOR          (1 << 25) -#define ZEND_CALL_DYNAMIC            (1 << 26) +#define ZEND_CALL_CLOSURE            (1 << 22) +#define ZEND_CALL_FAKE_CLOSURE       (1 << 23) +#define ZEND_CALL_GENERATOR          (1 << 24) +#define ZEND_CALL_DYNAMIC            (1 << 25)  #define ZEND_CALL_SEND_ARG_BY_REF    (1 << 31)  #define ZEND_CALL_NESTED_FUNCTION    (ZEND_CALL_FUNCTION | ZEND_CALL_NESTED) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 1d626a0def..3877981ad0 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 b350e77541..8b635970bb 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2803,16 +2803,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)));  		} @@ -2834,16 +2825,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)));  		} @@ -4034,7 +4016,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(); @@ -4113,16 +4094,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); @@ -5354,7 +5326,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_HAS_THIS, +			ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS,  			constructor,  			opline->extended_value,  			Z_OBJ_P(result)); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index e8f22d7cbc..d7872068f9 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(); @@ -1286,16 +1267,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); @@ -1313,7 +1285,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(); @@ -1392,16 +1363,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); @@ -9124,7 +9086,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_HAS_THIS, +			ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS,  			constructor,  			opline->extended_value,  			Z_OBJ_P(result)); @@ -29469,7 +29431,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_HAS_THIS, +			ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS,  			constructor,  			opline->extended_value,  			Z_OBJ_P(result)); @@ -37307,7 +37269,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_HAS_THIS, +			ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS,  			constructor,  			opline->extended_value,  			Z_OBJ_P(result)); @@ -60313,16 +60275,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)));  		} @@ -60344,16 +60297,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)));  		}  | 
