]> granicus.if.org Git - php/commitdiff
Don't relay on reference-counter when parameter expected to be a reference, but value...
authorDmitry Stogov <dmitry@zend.com>
Fri, 3 Apr 2015 13:35:06 +0000 (16:35 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 3 Apr 2015 13:35:06 +0000 (16:35 +0300)
Zend/tests/bug29890.phpt
Zend/zend_execute_API.c
Zend/zend_types.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/spl/spl_array.c
ext/standard/tests/array/array_map_variation2.phpt

index 32e8e1bd5dba22e541284c001d947e946f9ed2f7..1fdcdc4291336363f361d48fab2f5072e23bbada 100644 (file)
@@ -2,7 +2,7 @@
 Bug #29890 (crash if error handler fails)
 --FILE--
 <?php
-function customErrorHandler($fErrNo,$fErrStr,$fErrFile,$fErrLine,&$fClass) {
+function customErrorHandler($fErrNo,$fErrStr,$fErrFile,$fErrLine,$fClass) {
 echo "error :".$fErrStr."\n";
 }
 
index b703f18915d36743d0508986bbcd0d001cda5930..d37c2cd1d8eb90e60e1a8546901fcb3e9cd76ff2 100644 (file)
@@ -670,7 +670,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
        zend_fcall_info_cache fci_cache_local;
        zend_function *func;
        zend_class_entry *orig_scope;
-       zval tmp;
 
        ZVAL_UNDEF(fci->retval);
 
@@ -775,26 +774,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
 
        for (i=0; i<fci->param_count; i++) {
                zval *param;
+               zval *arg = &fci->params[i];
 
                if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
-                       // TODO: Scalar values don't have reference counters anymore.
-                       // They are assumed to be 1, and they may be easily passed by
-                       // reference now. However, previously scalars with refcount==1
-                       // might be passed and with refcount>1 might not. We can support
-                       // only single behavior ???
-#if 0
-                       if (Z_REFCOUNTED(fci->params[i]) &&
-                               // This solution breaks the following test (omit warning message) ???
-                               // Zend/tests/bug61273.phpt
-                               // ext/reflection/tests/bug42976.phpt
-                               // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
-#else
-                       if (!Z_REFCOUNTED(fci->params[i]) ||
-                               // This solution breaks the following test (emit warning message) ???
-                               // ext/pdo_sqlite/tests/pdo_005.phpt
-#endif
-                           (!Z_ISREF(fci->params[i]) && Z_REFCOUNT(fci->params[i]) > 1)) {
-
+                       if (UNEXPECTED(!Z_ISREF_P(arg))) {
                                if (fci->no_separation &&
                                        !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
                                        if (i) {
@@ -815,29 +798,21 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
                                        return FAILURE;
                                }
 
-                               if (Z_REFCOUNTED(fci->params[i])) {
-                                       Z_DELREF(fci->params[i]);
-                               }
-                               ZVAL_DUP(&tmp, &fci->params[i]);
-                               ZVAL_NEW_REF(&fci->params[i], &tmp);
-                               Z_ADDREF(fci->params[i]);
-                       } else if (!Z_ISREF(fci->params[i])) {
-                               ZVAL_NEW_REF(&fci->params[i], &fci->params[i]);
-                               Z_ADDREF(fci->params[i]);
-                       } else if (Z_REFCOUNTED(fci->params[i])) {
-                               Z_ADDREF(fci->params[i]);
+                               ZVAL_NEW_REF(arg, arg);
                        }
-                       param = ZEND_CALL_ARG(call, i+1);
-                       ZVAL_COPY_VALUE(param, &fci->params[i]);
-               } else if (Z_ISREF(fci->params[i]) &&
-                          /* don't separate references for __call */
-                          (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
-                       param = ZEND_CALL_ARG(call, i+1);
-                       ZVAL_DUP(param, Z_REFVAL(fci->params[i]));
+                       Z_ADDREF_P(arg);
                } else {
-                       param = ZEND_CALL_ARG(call, i+1);
-                       ZVAL_COPY(param, &fci->params[i]);
+                       if (Z_ISREF_P(arg) &&
+                           (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
+                               /* don't separate references for __call */
+                               arg = Z_REFVAL_P(arg);
+                       }
+                       if (Z_OPT_REFCOUNTED_P(arg)) {
+                               Z_ADDREF_P(arg);
+                       }
                }
+               param = ZEND_CALL_ARG(call, i+1);
+               ZVAL_COPY_VALUE(param, arg);
        }
 
        EG(scope) = calling_scope;
index 369f20f56f90432ff309936f27e73d64c0c0a115..a7d8d9961175aa83b149b210eb9ecbc2be090f2d 100644 (file)
@@ -699,6 +699,14 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
                Z_TYPE_INFO_P(__z) = IS_REFERENCE_EX;                                   \
        } while (0)
 
+#define ZVAL_NEW_EMPTY_REF(z) do {                                                             \
+               zend_reference *_ref = emalloc(sizeof(zend_reference)); \
+               GC_REFCOUNT(_ref) = 1;                                                                  \
+               GC_TYPE_INFO(_ref) = IS_REFERENCE;                                              \
+               Z_REF_P(z) = _ref;                                                                              \
+               Z_TYPE_INFO_P(z) = IS_REFERENCE_EX;                                             \
+       } while (0)
+
 #define ZVAL_NEW_REF(z, r) do {                                                                        \
                zend_reference *_ref = emalloc(sizeof(zend_reference)); \
                GC_REFCOUNT(_ref) = 1;                                                                  \
index 4dd9a1f4485d143c43d3fe62c5e90f4149fddd5e..91d541ab4cf8bd05a490ce82bb77f2f629260c71 100644 (file)
@@ -4381,7 +4381,7 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY)
        } else {
                uint32_t arg_num;
                HashTable *ht;
-               zval *arg, *param, tmp;
+               zval *arg, *param;
 
 ZEND_VM_C_LABEL(send_array):
                ht = Z_ARRVAL_P(args);
@@ -4407,24 +4407,7 @@ ZEND_VM_C_LABEL(send_array):
                param = ZEND_CALL_ARG(EX(call), 1);
                ZEND_HASH_FOREACH_VAL(ht, arg) {
                        if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
-                               // TODO: Scalar values don't have reference counters anymore.
-                               // They are assumed to be 1, and they may be easily passed by
-                               // reference now. However, previously scalars with refcount==1
-                               // might be passed and with refcount>1 might not. We can support
-                               // only single behavior ???
-#if 0
-                               if (Z_REFCOUNTED_P(arg) &&
-                                       // This solution breaks the following test (omit warning message) ???
-                                       // Zend/tests/bug61273.phpt
-                                       // ext/reflection/tests/bug42976.phpt
-                                       // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
-#else
-                               if (!Z_REFCOUNTED_P(arg) ||
-                                       // This solution breaks the following test (emit warning message) ???
-                                       // ext/pdo_sqlite/tests/pdo_005.phpt
-#endif
-                                   (!Z_ISREF_P(arg) && Z_REFCOUNT_P(arg) > 1)) {
-
+                               if (UNEXPECTED(!Z_ISREF_P(arg))) {
                                        if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
 
                                                zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
@@ -4446,26 +4429,20 @@ ZEND_VM_C_LABEL(send_array):
                                                break;
                                        }
 
-                                       if (Z_REFCOUNTED_P(arg)) {
-                                               Z_DELREF_P(arg);
-                                       }
-                                       ZVAL_DUP(&tmp, arg);
-                                       ZVAL_NEW_REF(arg, &tmp);
-                                       Z_ADDREF_P(arg);
-                               } else if (!Z_ISREF_P(arg)) {
                                        ZVAL_NEW_REF(arg, arg);
-                                       Z_ADDREF_P(arg);
-                               } else if (Z_REFCOUNTED_P(arg)) {
+                               }
+                               Z_ADDREF_P(arg);
+                       } else{
+                               if (Z_ISREF_P(arg) &&
+                                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                                       /* don't separate references for __call */
+                                       arg = Z_REFVAL_P(arg);
+                               }
+                               if (Z_OPT_REFCOUNTED_P(arg)) {
                                        Z_ADDREF_P(arg);
                                }
-                               ZVAL_COPY_VALUE(param, arg);
-                       } else if (Z_ISREF_P(arg) &&
-                          /* don't separate references for __call */
-                          (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
-                               ZVAL_DUP(param, Z_REFVAL_P(arg));
-                       } else {
-                               ZVAL_COPY(param, arg);
                        }
+                       ZVAL_COPY_VALUE(param, arg);
                        ZEND_CALL_NUM_ARGS(EX(call))++;
                        arg_num++;
                        param++;
@@ -4479,7 +4456,7 @@ ZEND_VM_C_LABEL(send_array):
 ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY)
 {
        USE_OPLINE
-       zval *arg, *param, tmp;
+       zval *arg, *param;
        zend_free_op free_op1;
 
        SAVE_OPLINE();
@@ -4487,23 +4464,7 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY)
        param = ZEND_CALL_VAR(EX(call), opline->result.var);
 
        if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
-               // TODO: Scalar values don't have reference counters anymore.
-               // They are assumed to be 1, and they may be easily passed by
-               // reference now. However, previously scalars with refcount==1
-               // might be passed and with refcount>1 might not. We can support
-               // only single behavior ???
-#if 0
-               if (Z_REFCOUNTED_P(arg) &&
-                       // This solution breaks the following test (omit warning message) ???
-                       // Zend/tests/bug61273.phpt
-                       // ext/reflection/tests/bug42976.phpt
-                       // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
-#else
-               if (!Z_REFCOUNTED_P(arg) ||
-                       // This solution breaks the following test (emit warning message) ???
-                       // ext/pdo_sqlite/tests/pdo_005.phpt
-#endif
-                   (!Z_ISREF_P(arg) /*&& Z_REFCOUNT_P(arg) > 1???*/)) {
+               if (UNEXPECTED(!Z_ISREF_P(arg))) {
 
                        if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
 
@@ -4529,26 +4490,20 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY)
                                ZEND_VM_NEXT_OPCODE();
                        }
 
-                       if (Z_REFCOUNTED_P(arg)) {
-                               Z_DELREF_P(arg);
-                       }
-                       ZVAL_DUP(&tmp, arg);
-                       ZVAL_NEW_REF(arg, &tmp);
-                       Z_ADDREF_P(arg);
-               } else if (!Z_ISREF_P(arg)) {
                        ZVAL_NEW_REF(arg, arg);
-                       Z_ADDREF_P(arg);
-               } else if (Z_REFCOUNTED_P(arg)) {
-                       Z_ADDREF_P(arg);
                }
-               ZVAL_COPY_VALUE(param, arg);
-       } else if (Z_ISREF_P(arg) &&
-                  /* don't separate references for __call */
-                  (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
-               ZVAL_DUP(param, Z_REFVAL_P(arg));
+               Z_ADDREF_P(arg);
        } else {
-               ZVAL_COPY(param, arg);
+               if (Z_ISREF_P(arg) &&
+                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                       /* don't separate references for __call */
+                       arg = Z_REFVAL_P(arg);
+               }
+               if (Z_OPT_REFCOUNTED_P(arg)) {
+                       Z_ADDREF_P(arg);
+               }
        }
+       ZVAL_COPY_VALUE(param, arg);
 
        FREE_OP1();
        CHECK_EXCEPTION();
index baa176529aff2ce3090f04a095edf79da7fce897..a03d07ae1c6acbae898172f62f8c83ccd37f3f7f 100644 (file)
@@ -1115,7 +1115,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O
        } else {
                uint32_t arg_num;
                HashTable *ht;
-               zval *arg, *param, tmp;
+               zval *arg, *param;
 
 send_array:
                ht = Z_ARRVAL_P(args);
@@ -1141,24 +1141,7 @@ send_array:
                param = ZEND_CALL_ARG(EX(call), 1);
                ZEND_HASH_FOREACH_VAL(ht, arg) {
                        if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
-                               // TODO: Scalar values don't have reference counters anymore.
-                               // They are assumed to be 1, and they may be easily passed by
-                               // reference now. However, previously scalars with refcount==1
-                               // might be passed and with refcount>1 might not. We can support
-                               // only single behavior ???
-#if 0
-                               if (Z_REFCOUNTED_P(arg) &&
-                                       // This solution breaks the following test (omit warning message) ???
-                                       // Zend/tests/bug61273.phpt
-                                       // ext/reflection/tests/bug42976.phpt
-                                       // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
-#else
-                               if (!Z_REFCOUNTED_P(arg) ||
-                                       // This solution breaks the following test (emit warning message) ???
-                                       // ext/pdo_sqlite/tests/pdo_005.phpt
-#endif
-                                   (!Z_ISREF_P(arg) && Z_REFCOUNT_P(arg) > 1)) {
-
+                               if (UNEXPECTED(!Z_ISREF_P(arg))) {
                                        if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
 
                                                zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
@@ -1180,26 +1163,20 @@ send_array:
                                                break;
                                        }
 
-                                       if (Z_REFCOUNTED_P(arg)) {
-                                               Z_DELREF_P(arg);
-                                       }
-                                       ZVAL_DUP(&tmp, arg);
-                                       ZVAL_NEW_REF(arg, &tmp);
-                                       Z_ADDREF_P(arg);
-                               } else if (!Z_ISREF_P(arg)) {
                                        ZVAL_NEW_REF(arg, arg);
-                                       Z_ADDREF_P(arg);
-                               } else if (Z_REFCOUNTED_P(arg)) {
+                               }
+                               Z_ADDREF_P(arg);
+                       } else{
+                               if (Z_ISREF_P(arg) &&
+                                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                                       /* don't separate references for __call */
+                                       arg = Z_REFVAL_P(arg);
+                               }
+                               if (Z_OPT_REFCOUNTED_P(arg)) {
                                        Z_ADDREF_P(arg);
                                }
-                               ZVAL_COPY_VALUE(param, arg);
-                       } else if (Z_ISREF_P(arg) &&
-                          /* don't separate references for __call */
-                          (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
-                               ZVAL_DUP(param, Z_REFVAL_P(arg));
-                       } else {
-                               ZVAL_COPY(param, arg);
                        }
+                       ZVAL_COPY_VALUE(param, arg);
                        ZEND_CALL_NUM_ARGS(EX(call))++;
                        arg_num++;
                        param++;
@@ -14012,7 +13989,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER(Z
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
-       zval *arg, *param, tmp;
+       zval *arg, *param;
        zend_free_op free_op1;
 
        SAVE_OPLINE();
@@ -14020,23 +13997,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
        param = ZEND_CALL_VAR(EX(call), opline->result.var);
 
        if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
-               // TODO: Scalar values don't have reference counters anymore.
-               // They are assumed to be 1, and they may be easily passed by
-               // reference now. However, previously scalars with refcount==1
-               // might be passed and with refcount>1 might not. We can support
-               // only single behavior ???
-#if 0
-               if (Z_REFCOUNTED_P(arg) &&
-                       // This solution breaks the following test (omit warning message) ???
-                       // Zend/tests/bug61273.phpt
-                       // ext/reflection/tests/bug42976.phpt
-                       // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
-#else
-               if (!Z_REFCOUNTED_P(arg) ||
-                       // This solution breaks the following test (emit warning message) ???
-                       // ext/pdo_sqlite/tests/pdo_005.phpt
-#endif
-                   (!Z_ISREF_P(arg) /*&& Z_REFCOUNT_P(arg) > 1???*/)) {
+               if (UNEXPECTED(!Z_ISREF_P(arg))) {
 
                        if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
 
@@ -14062,26 +14023,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
                                ZEND_VM_NEXT_OPCODE();
                        }
 
-                       if (Z_REFCOUNTED_P(arg)) {
-                               Z_DELREF_P(arg);
-                       }
-                       ZVAL_DUP(&tmp, arg);
-                       ZVAL_NEW_REF(arg, &tmp);
-                       Z_ADDREF_P(arg);
-               } else if (!Z_ISREF_P(arg)) {
                        ZVAL_NEW_REF(arg, arg);
-                       Z_ADDREF_P(arg);
-               } else if (Z_REFCOUNTED_P(arg)) {
-                       Z_ADDREF_P(arg);
                }
-               ZVAL_COPY_VALUE(param, arg);
-       } else if (Z_ISREF_P(arg) &&
-                  /* don't separate references for __call */
-                  (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
-               ZVAL_DUP(param, Z_REFVAL_P(arg));
+               Z_ADDREF_P(arg);
        } else {
-               ZVAL_COPY(param, arg);
+               if (Z_ISREF_P(arg) &&
+                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                       /* don't separate references for __call */
+                       arg = Z_REFVAL_P(arg);
+               }
+               if (Z_OPT_REFCOUNTED_P(arg)) {
+                       Z_ADDREF_P(arg);
+               }
        }
+       ZVAL_COPY_VALUE(param, arg);
 
        zval_ptr_dtor_nogc(free_op1);
        CHECK_EXCEPTION();
@@ -27605,7 +27560,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_HANDLER(ZE
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
-       zval *arg, *param, tmp;
+       zval *arg, *param;
 
 
        SAVE_OPLINE();
@@ -27613,23 +27568,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
        param = ZEND_CALL_VAR(EX(call), opline->result.var);
 
        if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
-               // TODO: Scalar values don't have reference counters anymore.
-               // They are assumed to be 1, and they may be easily passed by
-               // reference now. However, previously scalars with refcount==1
-               // might be passed and with refcount>1 might not. We can support
-               // only single behavior ???
-#if 0
-               if (Z_REFCOUNTED_P(arg) &&
-                       // This solution breaks the following test (omit warning message) ???
-                       // Zend/tests/bug61273.phpt
-                       // ext/reflection/tests/bug42976.phpt
-                       // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
-#else
-               if (!Z_REFCOUNTED_P(arg) ||
-                       // This solution breaks the following test (emit warning message) ???
-                       // ext/pdo_sqlite/tests/pdo_005.phpt
-#endif
-                   (!Z_ISREF_P(arg) /*&& Z_REFCOUNT_P(arg) > 1???*/)) {
+               if (UNEXPECTED(!Z_ISREF_P(arg))) {
 
                        if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
 
@@ -27654,26 +27593,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
                                ZEND_VM_NEXT_OPCODE();
                        }
 
-                       if (Z_REFCOUNTED_P(arg)) {
-                               Z_DELREF_P(arg);
-                       }
-                       ZVAL_DUP(&tmp, arg);
-                       ZVAL_NEW_REF(arg, &tmp);
-                       Z_ADDREF_P(arg);
-               } else if (!Z_ISREF_P(arg)) {
                        ZVAL_NEW_REF(arg, arg);
-                       Z_ADDREF_P(arg);
-               } else if (Z_REFCOUNTED_P(arg)) {
-                       Z_ADDREF_P(arg);
                }
-               ZVAL_COPY_VALUE(param, arg);
-       } else if (Z_ISREF_P(arg) &&
-                  /* don't separate references for __call */
-                  (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
-               ZVAL_DUP(param, Z_REFVAL_P(arg));
+               Z_ADDREF_P(arg);
        } else {
-               ZVAL_COPY(param, arg);
+               if (Z_ISREF_P(arg) &&
+                   (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) {
+                       /* don't separate references for __call */
+                       arg = Z_REFVAL_P(arg);
+               }
+               if (Z_OPT_REFCOUNTED_P(arg)) {
+                       Z_ADDREF_P(arg);
+               }
        }
+       ZVAL_COPY_VALUE(param, arg);
 
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
index 12abb704aa7284c8970bb76782de9bfb003c4542..5e62bad6e452334a5d7f7c1334a93cdbdcdec91f 100644 (file)
@@ -1474,49 +1474,49 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam
 {
        spl_array_object *intern = Z_SPLARRAY_P(getThis());
        HashTable *aht = spl_array_get_hash_table(intern, 0);
-       zval tmp, *arg = NULL;
-       zval retval;
+       zval function_name, params[2], *arg = NULL;
        uint32_t old_refcount;
 
+       ZVAL_STRINGL(&function_name, fname, fname_len);
+
        /* A tricky way to pass "aht" by reference, reset refcount */
        //??? It may be not safe, if user comparison handler accesses "aht"
        old_refcount = GC_REFCOUNT(aht);
        GC_REFCOUNT(aht) = 1;
-       ZVAL_ARR(&tmp, aht);
+       ZVAL_NEW_EMPTY_REF(&params[0]);
+       ZVAL_ARR(Z_REFVAL(params[0]), aht);
 
        if (!use_arg) {
                aht->u.v.nApplyCount++;
-               zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval, 1, &tmp, NULL);
+               call_user_function_ex(EG(function_table), NULL, &function_name, return_value, 1, params, 1, NULL);
                aht->u.v.nApplyCount--;
        } else if (use_arg == SPL_ARRAY_METHOD_MAY_USER_ARG) {
                if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) {
-                       GC_REFCOUNT(aht) = old_refcount;
                        zend_throw_exception(spl_ce_BadMethodCallException, "Function expects one argument at most", 0);
-                       return;
+                       goto exit;
+               }
+               if (arg) {
+                       ZVAL_COPY_VALUE(&params[1], arg);
                }
                aht->u.v.nApplyCount++;
-               zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval, arg? 2 : 1, &tmp, arg);
+               call_user_function_ex(EG(function_table), NULL, &function_name, return_value, arg ? 2 : 1, params, 1, NULL);
                aht->u.v.nApplyCount--;
        } else {
                if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
-                       GC_REFCOUNT(aht) = old_refcount;
                        zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0);
-                       return;
+                       goto exit;
                }
+               ZVAL_COPY_VALUE(&params[1], arg);
                aht->u.v.nApplyCount++;
-               zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval, 2, &tmp, arg);
+               call_user_function_ex(EG(function_table), NULL, &function_name, return_value, 2, params, 1, NULL);
                aht->u.v.nApplyCount--;
        }
+
+exit:
        /* 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_REF(tmp));
-       }
        GC_REFCOUNT(aht) = old_refcount;
-       if (!Z_ISUNDEF(retval)) {
-               ZVAL_COPY_VALUE(return_value, &retval);
-       }
+       efree(Z_REF(params[0]));
+       zend_string_free(Z_STR(function_name));
 } /* }}} */
 
 #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
index 16561abffc1f7fd5989f3d43ce1a508f37e2020e..b24aa07bc40d5a9e48a495490cc52358af8b0741 100644 (file)
@@ -77,16 +77,7 @@ array(4) {
       [0]=>
       &string(2) "v1"
       [1]=>
-      &array(4) {
-        ["k1"]=>
-        &string(2) "v1"
-        ["k2"]=>
-        string(2) "v2"
-        [0]=>
-        &string(2) "v1"
-        [1]=>
-        *RECURSION*
-      }
+      *RECURSION*
     }
   }
 }