Skip to content

Fix GH-21700: undefined behavior in _php_stream_seek with user stream returning negative position#21914

Open
lacatoire wants to merge 1 commit intophp:masterfrom
lacatoire:fix/21700-stream-seek-negative-position
Open

Fix GH-21700: undefined behavior in _php_stream_seek with user stream returning negative position#21914
lacatoire wants to merge 1 commit intophp:masterfrom
lacatoire:fix/21700-stream-seek-negative-position

Conversation

@lacatoire
Copy link
Copy Markdown
Member

Fixes GH-21700.

When a user stream's stream_tell() returns a negative offset after a stream_seek() reported success, _php_stream_seek would store that value into stream->position and then trip ZEND_ASSERT(stream->position >= 0) on the next SEEK_CUR (or any subsequent SEEK_CUR-based op).

Two changes:

  • After the SEEK_CUR → SEEK_SET conversion, fall through to the existing offset < 0 rejection so a SEEK_CUR whose absolute target is negative is refused before invoking the user seek hook.
  • After stream->ops->seek returns success, validate stream->position is non-negative. If a user stream lied (e.g. stream_tell() returns -42), restore the prior position and return -1, matching POSIX fseek()'s contract that the file-position indicator is unchanged on failure.

Includes a regression phpt covering both paths.

…am returning negative position

When a user stream's stream_tell() returns a negative offset after a
stream_seek() reported success, _php_stream_seek would store that value
into stream->position and then trip ZEND_ASSERT(stream->position >= 0)
on the next SEEK_CUR.

Three changes:

- After the SEEK_CUR -> SEEK_SET conversion, fall through to the
  existing 'offset < 0' rejection so a SEEK_CUR whose absolute target
  would be negative is refused before invoking the user seek hook.

- After stream->ops->seek returns success, validate stream->position is
  non-negative. If a user stream lied (e.g. stream_tell() returns -42),
  restore the prior position and return -1, matching POSIX fseek()'s
  contract that the file-position indicator is unchanged on failure.

- In php_stream_open_wrapper_ex's append-mode position fixup, ignore a
  negative newpos returned by stream->ops->seek (defense in depth for
  the only other direct caller of the seek hook in this layer).

Includes phpt regression tests covering both _php_stream_seek paths and
the append-mode open path.
@lacatoire lacatoire force-pushed the fix/21700-stream-seek-negative-position branch from 471818b to 225fa9e Compare April 30, 2026 10:08
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.

Assertion failure _php_stream_seek at streams/streams.c

1 participant