summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/spl/spl_array.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index cf12aa6a66..ae817a0b8a 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -1436,9 +1436,10 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam
zval tmp, *arg = NULL;
zval retval;
- // ??? how to pass aht as a reference to later method call?
- array_init(&tmp);
- zend_hash_copy(Z_ARRVAL(tmp), aht, (copy_ctor_func_t)zval_add_ref);
+ /* A tricky way to pass "aht" by reference, copy HashTable */
+ //??? It may be not safe, if user comparison handler accesses "aht"
+ ZVAL_NEW_ARR(&tmp);
+ *Z_ARRVAL(tmp) = *aht;
if (!use_arg) {
aht->nApplyCount++;
@@ -1463,7 +1464,13 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam
zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval, 2, &tmp, arg TSRMLS_CC);
aht->nApplyCount--;
}
- zval_ptr_dtor(&tmp);
+ /* A tricky way to pass "aht" by reference, copy back and cleanup */
+ if (Z_ISREF(tmp) && Z_TYPE_P(Z_REFVAL(tmp))) {
+ *aht = *Z_ARRVAL_P(Z_REFVAL(tmp));
+ GC_REMOVE_FROM_BUFFER(Z_ARR_P(Z_REFVAL(tmp)));
+ efree(Z_ARR_P(Z_REFVAL(tmp)));
+ efree(Z_REF(tmp));
+ }
if (!ZVAL_IS_UNDEF(&retval)) {
COPY_PZVAL_TO_ZVAL(*return_value, &retval);
}