From a917840f38a4743020e0d8a16fcaf23826a87500 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 17 Dec 2015 23:21:48 +0100 Subject: [PATCH] Fixed iter leak on by-ref foreach over const/tmp array FE_FREE does not unregister the iter for plain arrays. So always wrap into a REF wrapper, even if not strictly necessary, in RESET_RW. Alternatively we could use a flag to distinguish plain positions and interators. Also added a check for leaked iterators in shutdown_executor. --- Zend/zend_execute_API.c | 6 ++++++ Zend/zend_vm_def.h | 5 +++-- Zend/zend_vm_execute.h | 20 ++++++++++++-------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fdffed34b27..6eafeb75500 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -397,6 +397,12 @@ void shutdown_executor(void) /* {{{ */ zend_shutdown_fpu(); +#ifdef ZEND_DEBUG + if (EG(ht_iterators_used)) { + zend_error(E_WARNING, "Leaked %" PRIu32 " hashtable iterators", EG(ht_iterators_used)); + } +#endif + EG(ht_iterators_used) = 0; if (EG(ht_iterators) != EG(ht_iterators_slots)) { efree(EG(ht_iterators)); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0e555f5f83a..f02a0e82482 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5854,8 +5854,9 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY) Z_ADDREF_P(array_ref); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref); } else { - array_ptr = EX_VAR(opline->result.var); - ZVAL_COPY_VALUE(array_ptr, array_ref); + array_ref = EX_VAR(opline->result.var); + ZVAL_NEW_REF(array_ref, array_ptr); + array_ptr = Z_REFVAL_P(array_ref); } if (OP1_TYPE == IS_CONST) { zval_copy_ctor_func(array_ptr); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 8ef0c4dbbfc..52a122c94a2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3833,8 +3833,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER Z_ADDREF_P(array_ref); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref); } else { - array_ptr = EX_VAR(opline->result.var); - ZVAL_COPY_VALUE(array_ptr, array_ref); + array_ref = EX_VAR(opline->result.var); + ZVAL_NEW_REF(array_ref, array_ptr); + array_ptr = Z_REFVAL_P(array_ref); } if (IS_CONST == IS_CONST) { zval_copy_ctor_func(array_ptr); @@ -12182,8 +12183,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z Z_ADDREF_P(array_ref); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref); } else { - array_ptr = EX_VAR(opline->result.var); - ZVAL_COPY_VALUE(array_ptr, array_ref); + array_ref = EX_VAR(opline->result.var); + ZVAL_NEW_REF(array_ref, array_ptr); + array_ptr = Z_REFVAL_P(array_ref); } if (IS_TMP_VAR == IS_CONST) { zval_copy_ctor_func(array_ptr); @@ -15627,8 +15629,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z Z_ADDREF_P(array_ref); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref); } else { - array_ptr = EX_VAR(opline->result.var); - ZVAL_COPY_VALUE(array_ptr, array_ref); + array_ref = EX_VAR(opline->result.var); + ZVAL_NEW_REF(array_ref, array_ptr); + array_ptr = Z_REFVAL_P(array_ref); } if (IS_VAR == IS_CONST) { zval_copy_ctor_func(array_ptr); @@ -29312,8 +29315,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE Z_ADDREF_P(array_ref); ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref); } else { - array_ptr = EX_VAR(opline->result.var); - ZVAL_COPY_VALUE(array_ptr, array_ref); + array_ref = EX_VAR(opline->result.var); + ZVAL_NEW_REF(array_ref, array_ptr); + array_ptr = Z_REFVAL_P(array_ref); } if (IS_CV == IS_CONST) { zval_copy_ctor_func(array_ptr);