diff options
-rw-r--r-- | Zend/tests/bug52060.phpt | 12 | ||||
-rw-r--r-- | Zend/zend_builtin_functions.c | 14 |
2 files changed, 23 insertions, 3 deletions
diff --git a/Zend/tests/bug52060.phpt b/Zend/tests/bug52060.phpt new file mode 100644 index 0000000000..fef603b0ca --- /dev/null +++ b/Zend/tests/bug52060.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #52060 (Memory leak when passing a closure to method_exists()) +--FILE-- +<?php + +$closure = function($a) { echo $a; }; + +var_dump(method_exists($closure, '__invoke')); // true + +?> +--EXPECT-- +bool(true) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 1dbaeda049..5151446814 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -26,6 +26,7 @@ #include "zend_ini.h" #include "zend_exceptions.h" #include "zend_extensions.h" +#include "zend_closures.h" #undef ZEND_TEST_EXCEPTIONS @@ -1104,22 +1105,29 @@ ZEND_FUNCTION(method_exists) RETURN_TRUE; } else { union _zend_function *func = NULL; - efree(lcname); if (Z_TYPE_P(klass) == IS_OBJECT && Z_OBJ_HT_P(klass)->get_method != NULL && (func = Z_OBJ_HT_P(klass)->get_method(&klass, method_name, method_len, NULL TSRMLS_CC)) != NULL ) { if (func->type == ZEND_INTERNAL_FUNCTION - && ((zend_internal_function*)func)->handler == zend_std_call_user_call + && (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0 ) { + /* Returns true to the fake Closure's __invoke */ + RETVAL_BOOL((func->common.scope == zend_ce_closure + && (method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) + && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0) ? 1 : 0); + + efree(lcname); efree(((zend_internal_function*)func)->function_name); efree(func); - RETURN_FALSE; + return; } + efree(lcname); RETURN_TRUE; } } + efree(lcname); RETURN_FALSE; } /* }}} */ |