https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118099

--- Comment #5 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jonathan Wakely <[email protected]>:

https://gcc.gnu.org/g:43e4d697586364decbad7f67a204189afef6e765

commit r17-5971-g43e4d697586364decbad7f67a204189afef6e765
Author: Jonathan Wakely <[email protected]>
Date:   Thu Oct 22 23:18:57 2026 +0100

    libstdc++: Avoid possible null pointer arithmetic in
basic_filebuf::overflow [PR118099]

    The unbuffered path in basic_filebuf::overflow calls
    _M_convert_to_external(&__conv, 1) to output a single character. But if
    a partial codecvt conversion happens in _M_convert_to_external then it
    calculates the number of unconverted characters in the filebuf's put
    area by calling pptr(). In the unbuffered case pptr() returns a null
    pointer and so the arithmetic on it is undefined.

    Although GCC doesn't diagnose this, Clang's UBSan does:
    .../include/c++/16/bits/fstream.tcc:655:19: runtime error: applying
non-zero offset to non-null pointer 0x7ffd0d20eca7 produced null pointer

    _M_convert_to_external should only read from the buffer passed to it,
    not assume that the streambuf's put area exists or is equivalent to the
    buffer that was passed.

    This probably isn't a problem in real code, because the null pptr() in
    _M_convert_to_external was only reachable for a non-conforming codecvt
    facet that lies about max_length() or for some reason performs a partial
    conversion on a single character even when sufficient output space is
    available (as in the new testcases).  But it is more robust to not
    access pptr() directly when we are called with a pointer to the sequence
    that should be converted. This also enables a further correctness fix to
    basic_filebuf::overflow in a subsequent commit.

    The retry code can be further simplified because not only is using
    pptr() unsafe, but we can just use [__iend, __ibuf + __ilen) as the
    input range, instead of [__iend, __iend + (pptr() - __iend)). That was
    just unnecessarily complicated.

    The retry_forcing_codecvt in the new test was generated by an LLM,
    although greatly simplified by me so that the bug is detected with a
    simple VERIFY rather than examining the characters output by the facet.

    Assisted-by: LLM

    libstdc++-v3/ChangeLog:

            PR libstdc++/118099
            * include/bits/fstream.tcc
            (basic_filebuf::_M_convert_to_external): Use __ibuf + __ilen
            instead of this->pptr().
            * testsuite/27_io/basic_filebuf/overflow/char/118099-unbuffered.cc:
            New test.
            *
testsuite/27_io/basic_filebuf/overflow/wchar_t/118099-unbuffered.cc:
            New test.

    Reviewed-by: Tomasz KamiÅski <[email protected]>

Reply via email to