[php-src] Issue #24579: Crash in FILTER_VALIDATE_INT when __toString() mutates the referenced options array

From: Date: Thu, 22 Oct 2026 20:42:58 +0000
Subject: [php-src] Issue #24579: Crash in FILTER_VALIDATE_INT when __toString() mutates the referenced options array
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-253116@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24579 Author: Meecoy ### Description # Crash in FILTER_VALIDATE_INT when __toString() mutates the referenced options array ## Summary Calling filter_var() with FILTER_VALIDATE_INT crashes when the input object implements __toString() and modifies the options array referenced by the filter arguments during string conversion. Reproduced on PHP 8.5.12. A non-debug build terminated with SIGSEGV. A debug build terminated with SIGABRT after Zend detected an inconsistent hash table state. ## Minimal reproducer ```php <?php $shared = ['min_range' => 0]; $args = ['options' => &$shared]; class Reenter { public function __toString(): string { global $shared; $shared = 'changed'; return '1'; } } filter_var(new Reenter(), FILTER_VALIDATE_INT, $args); ``` ## Steps to reproduce 1. Build PHP 8.5.12 from php-src with the Filter extension enabled. 2. Run the script above using the built PHP binary. Build configuration used on Arch Linux: ```bash ./buildconf --force ./configure --disable-all --enable-cli --enable-debug --enable-filter \ CFLAGS="-O0 -g3 -fno-omit-frame-pointer" make -j"$(nproc)" ``` Run the reproducer: ```bash ./sapi/cli/php repro.php ``` ## Observed behavior In the debug build, execution terminates with an assertion failure similar to: ```text Zend/zend_hash.c(2919) : ht=0x7ffff78027c0 is being cleaned php: Zend/zend_hash.c:73: _zend_is_inconsistent: Assertion `0' failed. Program received signal SIGABRT ``` The backtrace points to zend_hash_str_find() called from php_filter_int(): ```text #5 _zend_is_inconsistent(...) #6 zend_hash_str_find(ht=0x7ffff78027c0, str="min_range", len=9) #7 php_filter_int(...) at ext/filter/logical_filters.c:213 #8 php_zval_filter(...) at ext/filter/filter.c:289 #9 php_filter_call(...) at ext/filter/filter.c:610 #10 zif_filter_var(...) at ext/filter/filter.c:787 ``` At frame 7, the option_array zval was observed to have type IS_STRING, while the filter code attempted to access it as a hash table through Z_ARRVAL_P(option_array). A non-debug build previously terminated with SIGSEGV for the same reproducer. ## Expected behavior The call should not crash the PHP process. If the options argument becomes invalid during reentrant execution, PHP should handle the situation safely, for example by rejecting invalid options or returning a filter failure according to the applicable API semantics. ## Initial investigation In ext/filter/logical_filters.c, the FETCH_LONG_OPTION macro accesses the options argument as a hash table: ```c #define FETCH_LONG_OPTION(var_name, option_name) \ var_name = 0; \ var_name##_set = 0; \ if (option_array) { \ if ((option_val = zend_hash_str_find( \ Z_ARRVAL_P(option_array), \ option_name, \ sizeof(option_name) - 1)) != NULL) { \ var_name = zval_get_long(option_val); \ var_name##_set = 1; \ } \ } ``` The macro checks whether option_array is non-null, but does not explicitly check that the zval is an array before passing its contents to zend_hash_str_find(). The filter call path performs string conversion on the input value before invoking the filter function. Since __toString() can execute userland code and mutate $shared, the options value may change during this conversion. This appears to create a reentrancy-related invalid-state condition in the filter options handling. The precise underlying mechanism has not yet been confirmed. ## Environment - PHP version: 8.5.12 - Operating system: Arch Linux - Build: locally compiled from php-src, with debug symbols - Configure options: --disable-all --enable-cli --enable-debug --enable-filter - Compiler optimization: -O0 ## Suggested investigation - Verify whether the options zval can be changed through the referenced argument during input string conversion. - Check whether the filter implementation should validate the zval type before using Z_ARRVAL_P(). - Review the relevant argument handling and ownership semantics in php_filter_call(), php_zval_filter(), and zif_filter_var(). - Add a regression test ensuring that reentrant mutation of the options argument cannot crash PHP. ### PHP Version ```plain PHP 8.5.12 (cli) (built: Oct 21 2026 20:05:19) (NTS) Copyright (c) The PHP Group Zend Engine v4.5.12, Copyright (c) Zend Technologies with Zend OPcache v8.5.12, Copyright (c), by Zend Technologies ``` ### Operating System Linux 7.2.8-2-cachyos

« previous php.bugs (#253116) next »