From d53f1bf8ab326a6fd3596a5f265d04bf49de74fe Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 18 Dec 2012 21:36:48 +0100 Subject: [PATCH] Fix leak when generator ignores sent value When the return value of yield wasn't used it was leaked. This is fixed by using a TMP_VAR return value instead of VAR. TMP_VARs are automatically freed when they aren't used. --- Zend/tests/generators/ignored_send_leak.phpt | 17 +++++ Zend/zend_compile.c | 2 +- Zend/zend_generators.c | 11 +-- Zend/zend_vm_def.h | 3 +- Zend/zend_vm_execute.h | 75 +++++++------------- 5 files changed, 47 insertions(+), 61 deletions(-) create mode 100644 Zend/tests/generators/ignored_send_leak.phpt diff --git a/Zend/tests/generators/ignored_send_leak.phpt b/Zend/tests/generators/ignored_send_leak.phpt new file mode 100644 index 0000000000..352ba406ba --- /dev/null +++ b/Zend/tests/generators/ignored_send_leak.phpt @@ -0,0 +1,17 @@ +--TEST-- +Ignoring a sent value shouldn't leak memory +--FILE-- +send(NULL); + +echo "DONE"; + +?> +--EXPECT-- +DONE diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ac3e633e28..d28b65af67 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2736,7 +2736,7 @@ void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_v SET_UNUSED(opline->op2); } - opline->result_type = IS_VAR; + opline->result_type = IS_TMP_VAR; opline->result.var = get_temporary_variable(CG(active_op_array)); GET_NODE(result, opline->result); } diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 9eae2c7019..d4254e090d 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -319,7 +319,7 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator ** if (orig->send_target) { size_t offset = (char *) orig->send_target - (char *)execute_data; clone->send_target = EX_TMP_VAR(clone->execute_data, offset); - Z_ADDREF_P(clone->send_target->var.ptr); + zval_copy_ctor(&clone->send_target->tmp_var); } if (execute_data->current_this) { @@ -641,13 +641,8 @@ ZEND_METHOD(Generator, send) return; } - /* The sent value was initialized to NULL, so dtor that */ - zval_ptr_dtor(&generator->send_target->var.ptr); - - /* Set new sent value */ - Z_ADDREF_P(value); - generator->send_target->var.ptr = value; - generator->send_target->var.ptr_ptr = &value; + /* Put sent value into the TMP_VAR slot */ + MAKE_COPY_ZVAL(&value, &generator->send_target->tmp_var); zend_generator_resume(generator TSRMLS_CC); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f7b10a29a6..c933a48248 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5371,8 +5371,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c077d5d2a5..dab0df3540 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4183,8 +4183,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -4879,8 +4878,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -5901,8 +5899,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -6616,8 +6613,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -7371,8 +7367,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -9417,8 +9412,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -10113,8 +10107,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -11135,8 +11128,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -11714,8 +11706,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -12407,8 +12398,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -16315,8 +16305,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -18403,8 +18392,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -20872,8 +20860,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -22014,8 +22001,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -24151,8 +24137,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -25642,8 +25627,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -26957,8 +26941,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -28273,8 +28256,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -28696,8 +28678,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -30008,8 +29989,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -33513,8 +33493,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -35468,8 +35447,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -37803,8 +37781,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -38802,8 +38779,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -40805,8 +40781,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS generator->send_target = &EX_T(opline->result.var); /* Initialize the sent value to NULL */ - Z_ADDREF(EG(uninitialized_zval)); - AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ -- 2.40.0