On Fri, 23 Oct 2026 at 18:44, Jonathan Wakely <[email protected]> wrote:
>
> On Fri, 23 Oct 2026 at 18:40, Jonathan Wakely <[email protected]> wrote:
> >
> > From: Peter Edwards <[email protected]>
> >
> > If we fail to write the content of the buffer after inserting the
> > overflow character into the end of it, then remove that overflow
> > character before propagating the error back to the caller. Without this,
> > the caller is left with pptr set past epptr, and successive calls to
> > overflow will write further past the end of the managed buffer with each
> > failure.
> >
> > libstdc++-v3/ChangeLog:
> >
> >         PR libstdc++/118099
> >         * include/bits/fstream.tcc (basic_filebuf::overflow): Rewind the
> >         put position if outputting the put area fails.
> >         * testsuite/27_io/basic_filebuf/overflow/char/118099.cc: New
> >         test.
> >         * testsuite/27_io/basic_filebuf/overflow/wchar_t/118099.cc:
> >         New test.
> >
> > Co-authored-by: Jonathan Wakely <[email protected]>
> > ---
> >
> > Tested x86_64-linux.
>
> I forgot to say:
> [PATCH 1/3] should be backported to active branches.
> [PATCH 2/3] is doesn't need to be backported since it only fixes a
> hypothetical problem.
> [PATCH 3/3] is not suitable for backporting, but the bug can be fixed
> with a try-catch around the call to _M_convert_to_external.

Or we could do this for the branches, which would fix the
non-hypothetical problems (and tests) fixed by PATCH 1/3 and 3/3:

--- a/libstdc++-v3/include/bits/fstream.tcc
+++ b/libstdc++-v3/include/bits/fstream.tcc
@@ -561,11 +561,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            }
         if (this->pbase() < this->pptr())
           {
+             struct _Guard {
+               ~_Guard() { if (_M_p) _M_p->pbump(-1); }
+               basic_filebuf* _M_p;
+             };
+             _Guard __g = { };
+
             // If appropriate, append the overflow char.
             if (!__testeof)
               {
                 *this->pptr() = traits_type::to_char_type(__c);
                 this->pbump(1);
+                 __g._M_p = this;
               }

             // Convert pending sequence to external representation,
@@ -573,6 +580,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
             if (_M_convert_to_external(this->pbase(),
                                        this->pptr() - this->pbase()))
               {
+                 __g._M_p = 0;
                 _M_set_buffer(0);
                 __ret = traits_type::not_eof(__c);
               }


For trunk I would still like to do the larger refactoring so that we
avoid advancing then conditionally rewinding the next pointer, and the
changes to _M_convert_to_external make it simpler IMHO.

Reply via email to