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

            Bug ID: 118099
           Summary: basic_filebuf::overflow is left inconsistent on I/O
                    error.
           Product: gcc
           Version: 14.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: peadar at arista dot com
  Target Milestone: ---

Created attachment 59904
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=59904&action=edit
Naive patch for issue.

The following illustrates the problem directly:
```
#include <bits/stdc++.h>
int main(int argc, char *argv[]) {
   std::ofstream of("/dev/full", std::ios_base::out);
   auto rdbuf = of.rdbuf();
   for (;;)
      rdbuf->sputc('x');
}
```

The same problem manifests writing to std::cout if you set
`std::ios_base::sync_with_stdio(false)`

when the buffer fills, sputc calls `std::basic_filebuf<char,
std::char_traits<char> >::overflow`, passing the character as the 'overflow'
character. basic_filebuf maintains space in the managed buffer for this
overflow, and inserts it into the buffer via *pptr()/pbump(1) - about line 560
of fstream.tcc
```
              if (!__testeof)
                  {
                    *this->pptr() = traits_type::to_char_type(__c);
                    this->pbump(1);
                  }
```

However, if the call to _M_convert_to_external fails (eventually due to the
write failing, in the above case because we fail to write to /dev/full), then
an error is returned, but the character is left sitting in the buffer, and pptr
> epptr.

A further call to sputc will hit the same point, and we will continue to write
further past the end of the managed buffer. 

Of course the caller should check for an error, but even if they do, the
streambuf is now in an inconsistent state, and there's no obvious approach to
recover - regardless of the memory scribble, we're returning with an error from
sputc(), but have also inserted the character we "failed" to write into the
buffer, which is inconsistent with the error return. So the simplest thing to
do here seems to be to just remove the character from the buffer . Dumb patch
attached, for what its worth.

This doesn't happen with std::cout if it's tied to C's stdout - the buffer is
managed differently and the problem doesn't manifest.

Reply via email to