diff --git a/Zend/tests/bug64280.phpt b/Zend/tests/bug64280.phpt new file mode 100644 index 0000000000000..15c75b148a5d6 --- /dev/null +++ b/Zend/tests/bug64280.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #64280 (__destruct loop segfaults) - Basic behaviour +--FILE-- + +--EXPECTF-- +Fatal error: Magic method or function too often called recursively in %s on line %d diff --git a/Zend/tests/bug64280_1.phpt b/Zend/tests/bug64280_1.phpt new file mode 100644 index 0000000000000..81efb8c565f83 --- /dev/null +++ b/Zend/tests/bug64280_1.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug #64280 (__destruct loop segfaults) - tests ini entry "max_magic_calls" and combining magic methods/functions with functions +--INI-- +max_magic_calls = 20 +--FILE-- += EG(max_implicit_fcalls)) { + zend_error_noreturn(E_ERROR, "Method or function too often called recursively by implicit call"); + } + EX(prev_execute_data) = EG(current_execute_data); EG(current_execute_data) = &execute_data; @@ -1022,6 +1026,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EG(scope) = current_scope; EG(This) = current_this; EG(current_execute_data) = EX(prev_execute_data); + --EG(implicit_fcall_count); if (EG(exception)) { zend_throw_exception_internal(NULL TSRMLS_CC); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 58392c199bd58..b594d80730933 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -5,7 +5,7 @@ | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | + | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.zend.com/license/2_00.txt. | | If you did not receive a copy of the Zend license and are unable to | @@ -236,11 +236,14 @@ struct _zend_executor_globals { /* timeout support */ int timeout_seconds; + long implicit_fcall_count; + long max_implicit_fcalls; + int lambda_count; HashTable *ini_directives; HashTable *modified_ini_directives; - zend_ini_entry *error_reporting_ini_entry; + zend_ini_entry *error_reporting_ini_entry; zend_objects_store objects_store; zval *exception, *prev_exception; @@ -253,7 +256,7 @@ struct _zend_executor_globals { zend_property_info std_property_info; - zend_bool active; + zend_bool active; zend_op *start_op; @@ -297,7 +300,7 @@ struct _zend_php_scanner_globals { unsigned char *yy_limit; int yy_state; zend_stack state_stack; - + /* original (unfiltered) script */ unsigned char *script_org; size_t script_org_size; diff --git a/main/main.c b/main/main.c index be289c8060839..b156a4426dd14 100644 --- a/main/main.c +++ b/main/main.c @@ -453,6 +453,23 @@ static PHP_INI_MH(OnChangeMailForceExtra) } /* }}} */ +/* {{{ PHP_INI_MH + */ +static PHP_INI_MH(OnChangeMaxImplicitFcalls) +{ + int intval = atoi(new_value); + /* strict minimum of 2, otherwise "normal" non recursive magic function calls may fail */ + if (intval > 1) { + if (!entry->orig_value || intval <= atoi(entry->orig_value)) { + OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); + return SUCCESS; + } + } + zend_error(E_WARNING, "max_implicit_function_calls ini-value has to be equal or less than php.ini value and greater than 1"); + return FAILURE; +} +/* }}} */ + /* defined in browscap.c */ PHP_INI_MH(OnChangeBrowscap); @@ -509,6 +526,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("short_open_tag", DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals) STD_PHP_INI_BOOLEAN("sql.safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, sql_safe_mode, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("track_errors", "0", PHP_INI_ALL, OnUpdateBool, track_errors, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("max_implicit_function_calls", "1000", PHP_INI_ALL, OnChangeMaxImplicitFcalls, max_implicit_fcalls, zend_executor_globals, executor_globals) STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateString, unserialize_callback_func, php_core_globals, core_globals) STD_PHP_INI_ENTRY("serialize_precision", "17", PHP_INI_ALL, OnUpdateLongGEZero, serialize_precision, php_core_globals, core_globals) diff --git a/php.ini-development b/php.ini-development index 4ff4192f6f84e..6ed6f727f3531 100644 --- a/php.ini-development +++ b/php.ini-development @@ -383,6 +383,11 @@ expose_php = On ; Note: This directive is hardcoded to 0 for the CLI SAPI max_execution_time = 30 +; Maximum nesting level of implicit function calls +; http://php.net/max-implicit-function-calls +; Note: If you set it too high, PHP may crash +;max_implicit_function_calls = 1000 + ; Maximum amount of time each script may spend parsing request data. It's a good ; idea to limit this time on productions servers in order to eliminate unexpectedly ; long running scripts. diff --git a/php.ini-production b/php.ini-production index 814455bbbbbfe..ffe7de025ec16 100644 --- a/php.ini-production +++ b/php.ini-production @@ -383,6 +383,11 @@ expose_php = On ; Note: This directive is hardcoded to 0 for the CLI SAPI max_execution_time = 30 +; Maximum nesting level of implicit function calls +; http://php.net/max-implicit-function-calls +; Note: If you set it too high, PHP may crash +;max_implicit_function_calls = 1000 + ; Maximum amount of time each script may spend parsing request data. It's a good ; idea to limit this time on productions servers in order to eliminate unexpectedly ; long running scripts.