summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2015-12-17 23:21:48 +0100
committerNikita Popov <nikic@php.net>2015-12-17 23:21:48 +0100
commita917840f38a4743020e0d8a16fcaf23826a87500 (patch)
tree9ce42a6c4c3b6a31cc671d65caba13ba534c38b8
parent6a4c02e107e86a0ff700b79f5a9da0f383c06430 (diff)
downloadphp-git-a917840f38a4743020e0d8a16fcaf23826a87500.tar.gz
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.
-rw-r--r--Zend/zend_execute_API.c6
-rw-r--r--Zend/zend_vm_def.h5
-rw-r--r--Zend/zend_vm_execute.h20
3 files changed, 21 insertions, 10 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index fdffed34b2..6eafeb7550 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 0e555f5f83..f02a0e8248 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 8ef0c4dbbf..52a122c94a 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);