[GIT-PULLS] [php-src] PR #23483: Fix fseek() accepting $whence values that do not fit in an int
[email protected] (lacatoire)
| Newsgroups | php.git-pulls |
|---|---|
| Message-ID | <[email protected]> |
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.