mirror of
https://github.com/fmtlib/fmt.git
synced 2026-06-17 17:37:20 +08:00
Fix hang/assertion when printing to a pipe with closed read end (#4797)
This commit is contained in:
parent
1be298e1bd
commit
9200553b22
@ -1526,7 +1526,10 @@ template <typename F> class file_base {
|
||||
FMT_THROW(system_error(errno, FMT_STRING("ungetc failed")));
|
||||
}
|
||||
|
||||
void flush() { fflush(this->file_); }
|
||||
void flush() {
|
||||
if (fflush(this->file_) != 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("fflush failed")));
|
||||
}
|
||||
};
|
||||
|
||||
// A FILE wrapper for glibc.
|
||||
@ -1572,7 +1575,10 @@ template <typename F> class glibc_file : public file_base<F> {
|
||||
return memchr(end, '\n', static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
void flush() { fflush_unlocked(this->file_); }
|
||||
void flush() {
|
||||
if (fflush_unlocked(this->file_) != 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("fflush failed")));
|
||||
}
|
||||
};
|
||||
|
||||
// A FILE wrapper for Apple's libc.
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include <cfenv> // fegetexceptflag and FE_ALL_EXCEPT
|
||||
#include <climits> // INT_MAX
|
||||
#include <cmath> // std::signbit
|
||||
#include <csignal> // std::signal, SIGPIPE
|
||||
#include <cstring> // std::strlen
|
||||
#include <iterator> // std::back_inserter
|
||||
#include <list> // std::list
|
||||
@ -2592,6 +2593,24 @@ TEST(format_test, invalid_glibc_buffer) {
|
||||
|
||||
fmt::print(file, "------\n");
|
||||
}
|
||||
|
||||
TEST(format_test, print_to_broken_pipe) {
|
||||
// Ignore SIGPIPE so that a failing write reports EPIPE instead of
|
||||
// terminating the test process. It must stay ignored until the file is
|
||||
// closed below because closing also flushes the remaining buffered data.
|
||||
auto old_handler = std::signal(SIGPIPE, SIG_IGN);
|
||||
{
|
||||
auto pipe = fmt::pipe();
|
||||
pipe.read_end.close();
|
||||
auto write_end = pipe.write_end.fdopen("w");
|
||||
|
||||
// The data must exceed the file's buffer to force a flush during
|
||||
// formatting, whose underlying write() then fails with EPIPE.
|
||||
auto data = std::string(1024 * 1024, 'x');
|
||||
EXPECT_THROW(fmt::print(write_end.get(), "{}", data), std::system_error);
|
||||
}
|
||||
std::signal(SIGPIPE, old_handler);
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
// Only defined after the test case.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user