https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127424
Bug ID: 127424
Summary: 27_io testsuite: opening a FIFO with O_RDWR is
undefined in POSIX; 9964.cc also stopped testing PR
9964 in 2004
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: gokbeykeskin at gmail dot com
Target Milestone: ---
Created attachment 65603
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65603&action=edit
patch file for my suggestion
Several tests under 27_io open a FIFO with ios_base::in|ios_base::out, which
fopen_mode() maps to "r+", i.e. O_RDWR. POSIX leaves this undefined:
O_RDWR
Open for reading and writing. The result is undefined if this flag is
applied to a FIFO.
Linux permits it, so the problem is invisible there, but it is not required.
On a target where opening a FIFO O_RDWR fails, the affected tests deadlock:
the process that issues the O_RDWR open fails to open the FIFO, so its peer
blocks forever in a blocking open() for the opposite direction, because the
FIFO never acquires a second endpoint.
27_io/basic_filebuf/showmanyc/char/9533-1.cc:58 child opens in|out
27_io/basic_filebuf/underflow/char/10097.cc:75 child opens in|out
27_io/basic_filebuf/seekoff/char/26777.cc:55 child opens in|out
27_io/objects/char/7.cc:56 child opens in|out
27_io/objects/char/9661-1.cc:56 child does fopen(name,
"r+")
27_io/basic_filebuf/close/char/9964.cc:65 PARENT opens in|out
None of these tests needs read-write access. In every case the process
opening in|out only ever writes. Opening write-only replaces the O_RDWR open
with the ordinary FIFO rendezvous (child O_WRONLY, parent O_RDONLY, or vice
versa), which is fully specified and introduces no ordering hazard.
Second, separate issue: close/char/9964.cc has not tested PR 9964 since 2004.
PR libstdc++/9964 was fixed by Petur Runolfsson on 2003-03-17:
PR libstdc++/9964
* include/bits/fstream.tcc (basic_filebuf::close):
Always close file, even when write fails.
The property is that when the flush at close time fails, close() must still
close the file -- reporting the failure by returning null, but still closing.
That is still what fstream.tcc does today: __close_sentry's destructor
tears down the buffer state unconditionally, _M_file.close() is called
unconditionally, and the return value is 0 only to report __testfail.
The test as originally committed opened the parent end write-only and asserted
exactly that:
filebuf* ret = fb.open(name, ios_base::out | ios_base::trunc);
...
ret = fb.close();
VERIFY( ret == NULL );
VERIFY( !fb.is_open() );
The write-only open is what makes the flush fail: the child closes the sole
read end, the parent's buffered 'a' meets a FIFO with no readers, SIGPIPE is
ignored, and write() fails with EPIPE.
r0-56237-g6a734d618f8 (2004-02-04, "Correct flags to filebuf::open calls",
the commit that introduced fopen_mode) changed both the mode and the
expectation:
- filebuf* ret = fb.open(name, ios_base::out | ios_base::trunc);
+ filebuf* ret = fb.open(name, ios_base::in | ios_base::out);
...
- VERIFY( ret == NULL );
+ VERIFY( ret != NULL );
With O_RDWR the parent holds its own read end, so the write at close succeeds
and the failure path is never entered. The test now passes whether or not the
PR 9964 fix is present, i.e. it is a dead regression test.
So the fix for this file is to restore the original write-only open and the
original close() expectation, which also removes its O_RDWR dependency.