Skip to content

Fix GH-24579: Validate option_array type before accessing as hash table - #24619

Closed
paezraphael wants to merge 1 commit into
php:masterfrom
paezraphael:fix-gh24579
Closed

paezraphael wants to merge 1 commit into
php:masterfrom
paezraphael:fix-gh24579

Conversation

@paezraphael

Copy link
Copy Markdown

Calling filter_var() with FILTER_VALIDATE_INT crashed when the input object implemented __toString() and modified the options array referenced by the filter arguments during string conversion.

The FETCH_*_OPTION macros checked if option_array was non-null but did not validate it was an array before using Z_ARRVAL_P(). When __toString() mutated the reference to a string, the code attempted to access it as a hash table, causing a crash (SIGSEGV in non-debug builds, assertion failure in debug builds).

This commit adds a Z_TYPE_P(option_array) == IS_ARRAY check to FETCH_LONG_OPTION, FETCH_DOUBLE_OPTION, and FETCH_STRING_OPTION to ensure the type is an array before accessing as a hash table.

Added regression test GH-24579.

Fixes GH-24579.

Generated with Devin

…table

Calling filter_var() with FILTER_VALIDATE_INT crashed when the input
object implemented __toString() and modified the options array referenced
by the filter arguments during string conversion.

The FETCH_*_OPTION macros checked if option_array was non-null but did not
validate it was an array before using Z_ARRVAL_P(). When __toString() mutated
the reference to a string, the code attempted to access it as a hash table,
causing a crash (SIGSEGV in non-debug builds, assertion failure in debug builds).

This commit adds a Z_TYPE_P(option_array) == IS_ARRAY check to
FETCH_LONG_OPTION, FETCH_DOUBLE_OPTION, and FETCH_STRING_OPTION to ensure
the type is an array before accessing as a hash table.

Added regression test phpGH-24579.

Fixes phpGH-24579.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@anun333

anun333 commented Oct 25, 2026

Copy link
Copy Markdown

Quoted below: written with Claude, an LLM, as CONTRIBUTING.md asks us to mark. The builds and test runs behind it are on my machine; the commands to repeat them are under the fold.

#24580 fixes GH-24579 as well. It was opened about 21 hours earlier, against PHP-8.4, the lowest branch with the bug; CONTRIBUTING.md asks for bug fixes there, and they are merged up to master.

I built both, in debug mode. With this PR (ff936a3a7d0 on master 3472eda4cb0) the crash is gone, gh24579.phpt passes, and ext/filter/tests gives 107 passed, 0 failed. But the filter still reads options changed during the call:

__toString() does master without a fix this PR #24580 (on PHP-8.4)
$shared = 'changed' (the issue) aborts int(1) int(1)
$shared = ['min_range' => 5] bool(false) bool(false) int(1)
$shared = ['min_range' => 5, 'default' => 42] int(42) int(42) int(1)

#24580 holds a counted copy of the options for the whole call, so it fixes the crash and keeps the options as they were passed.

How this was tested

Builds (Linux x86_64, gcc 13.3), each tree the same way:

./buildconf --force
./configure --enable-debug --with-mysqli --disable-cgi --disable-phpdbg --disable-fileinfo
make -j6

Each row is this script with the assignment in __toString() changed, run as sapi/cli/php -n case.php:

<?php
$shared = ['min_range' => 0]; $args = ['options' => &$shared];
class R { function __toString(): string { global $shared; $shared = ['min_range' => 5]; return '1'; } }
var_dump(filter_var(new R, FILTER_VALIDATE_INT, $args));

Unfixed master, first row:

Zend/zend_hash.c(2933) : ht=0x… is being cleaned
php: Zend/zend_hash.c:72: _zend_is_inconsistent: Assertion `0' failed.

@paezraphael

Copy link
Copy Markdown
Author

Closing in favor of #24580, which fixes GH-24579 as well.

#24580 was opened first, targets PHP-8.4 (the lowest affected branch, per CONTRIBUTING.md), and is more complete: it holds a counted copy of the options for the whole call, so besides fixing the crash it also keeps the options as they were passed, rather than reading values mutated during __toString(). My PR only adds the IS_ARRAY type check, which stops the crash but still reads the mutated array.

Thanks @anun333 for the side-by-side testing that made the difference clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash in FILTER_VALIDATE_INT when __toString() mutates the referenced options array

2 participants