https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114879
Bug ID: 114879 Summary: std::ios::sync_with_stdio(false) triggers undefined behaviour of fflush(stdin) Product: gcc Version: 13.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: campbell+gcc-bugzilla at mumble dot net Target Milestone: --- std::ios::sync_with_stdio(false) creates a stdio_filebuf over stdin with mode in: 182 new (&buf_cin) stdio_filebuf<char>(stdin, ios_base::in); https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc;h=ace94b992b5ac7559352f5e7e94c67f64317bd9d;hb=c891d8dc23e1a46ad9f3e757d09e57b500d40044#l182 The stdio_filebuf constructor for these parameter types passes the arguments on to __basic_file<char>::sys_open: 158 this->_M_file.sys_open(__f, __mode); https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/ext/stdio_filebuf.h;h=98b8fa2a095acf190237887d4e21394212d1f38a;hb=c891d8dc23e1a46ad9f3e757d09e57b500d40044#l158 With these parameter types, __basic_file<char>::sys_open will, in turn, pass stdin to fflush in this case, and will only actually open the file if fflush succeeds: 216 do 217 __err = fflush(__file); 218 while (__err && errno == EINTR); 219 errno = __save_errno; 220 if (!__err) 221 { 222 _M_cfile = __file; 223 _M_cfile_created = false; 224 __ret = this; 225 } https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/config/io/basic_file_stdio.cc;h=27c2ad2afe3ade7284ec9d487b74d3d04dd756f4;hb=c891d8dc23e1a46ad9f3e757d09e57b500d40044#l216 But stdin is an input stream, not an output or update stream. And calling fflush on an input stream is undefined behaviour in standard C: > If stream points to an output stream or an update stream in which > the most recent operation was not input, the fflush function causes > any unwritten data for that stream to be delivered to the host > environment to be written to the file; otherwise, the behavior is > undefined. > > (ISO C11 and ISO C17, Sec. 7.21.5.2 `The fflush function') On NetBSD 9, what fflush(stdin) does depends on whether fd 0 is open for writing or not: - If fd 0 is open for writing (unlikely but possible), it will write a buffer's worth of heap garbage to fd 0. - If fd 0 is not open for writing (more likely), fflush will fail with EBADF, causing __basic_file<char>::sys_open to fail, after which although std::cin.good() will initially return true, std::cin will otherwise be nonfunctional (https://gnats.NetBSD.org/58206). Fix: Don't call fflush if the mode is input. (This bug first appeared no later than GCC 7, which NetBSD 9 ships with and where I found the bug, and still appears in GCC 13.2.0, as quoted in the code above.)