[php-src] PR #23483: Fix fseek() accepting $whence values that do not fit in an int
| From: | lacatoire | Date: | Thu, 27 Aug 2026 20:19:55 +0000 |
| Subject: | [php-src] PR #23483: Fix fseek() accepting $whence values that do not fit in an int | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-38174@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/23483
Author: lacatoire
fseek() parses $whence as a zend_long, but casts it to a C
int when calling php_stream_seek(). Values whose low 32 bits alias onto a
valid seek constant are accepted and acted upon.
On a 64-bit build, with a 10-byte file and the cursor at 4:
```
fseek($h, 3, SEEK_CUR + 2**32) => 0 position 7 (treated as SEEK_CUR)
fseek($h, 3, PHP_INT_MIN) => 0 position 3 (treated as SEEK_SET)
fseek($h, 3, SEEK_END + 2**32) => 0 position 13 (treated as SEEK_END)
```
A return value of 0 means success, so the call reports that a seek nobody asked for
went through.
The fix rejects values outside the int range before the cast:
```c
if (whence < INT_MIN || whence > INT_MAX) {
RETURN_LONG(-1);
}
```
-1 is not a new convention: it is already what fseek() returns for an
invalid $whence that happens to fit in an int, and the position is left
untouched in both cases.
```
fseek($h, 3, 99) => -1 position unchanged
```
Platform constants such as SEEK_DATA (3) and SEEK_HOLE (4) fit in an
int and are unaffected.
ext/standard/tests/file/fseek_whence_overflow.phpt covers the three aliasing forms and
a plain SEEK_CUR as a regression guard. It skips on 32-bit builds, where no
zend_long can exceed an int.
Tested on a 64-bit Linux build: the new test passes, and ext/standard/tests/file,
ext/standard/tests/streams and ext/standard/tests/filters show no
regression.