diff options
Diffstat (limited to 'absl/strings')
-rw-r--r-- | absl/strings/internal/str_format/output.cc | 27 | ||||
-rw-r--r-- | absl/strings/str_format_test.cc | 5 |
2 files changed, 28 insertions, 4 deletions
diff --git a/absl/strings/internal/str_format/output.cc b/absl/strings/internal/str_format/output.cc index 5c3795b737ca..d7fef69b4cf9 100644 --- a/absl/strings/internal/str_format/output.cc +++ b/absl/strings/internal/str_format/output.cc @@ -20,6 +20,16 @@ namespace absl { namespace str_format_internal { +namespace { +struct ClearErrnoGuard { + ClearErrnoGuard() : old_value(errno) { errno = 0; } + ~ClearErrnoGuard() { + if (!errno) errno = old_value; + } + int old_value; +}; +} // namespace + void BufferRawSink::Write(string_view v) { size_t to_write = std::min(v.size(), size_); std::memcpy(buffer_, v.data(), to_write); @@ -30,14 +40,27 @@ void BufferRawSink::Write(string_view v) { void FILERawSink::Write(string_view v) { while (!v.empty() && !error_) { + // Reset errno to zero in case the libc implementation doesn't set errno + // when a failure occurs. + ClearErrnoGuard guard; + if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) { // Some progress was made. count_ += result; v.remove_prefix(result); } else { - // Some error occurred. - if (errno != EINTR) { + if (errno == EINTR) { + continue; + } else if (errno) { error_ = errno; + } else if (std::ferror(output_)) { + // Non-POSIX compliant libc implementations may not set errno, so we + // have check the streams error indicator. + error_ = EBADF; + } else { + // We're likely on a non-POSIX system that encountered EINTR but had no + // way of reporting it. + continue; } } } diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index ea9a3a176612..87ed234fe825 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc @@ -242,6 +242,7 @@ class TempFile { std::string ReadFile() { std::fseek(file_, 0, SEEK_END); int size = std::ftell(file_); + EXPECT_GT(size, 0); std::rewind(file_); std::string str(2 * size, ' '); int read_bytes = std::fread(&str[0], 1, str.size(), file_); @@ -270,7 +271,7 @@ TEST_F(FormatEntryPointTest, FPrintFError) { EXPECT_EQ(errno, EBADF); } -#if __GNUC__ +#if __GLIBC__ TEST_F(FormatEntryPointTest, FprintfTooLarge) { std::FILE* f = std::fopen("/dev/null", "w"); int width = 2000000000; @@ -297,7 +298,7 @@ TEST_F(FormatEntryPointTest, PrintF) { EXPECT_EQ(result, 30); EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019"); } -#endif // __GNUC__ +#endif // __GLIBC__ TEST_F(FormatEntryPointTest, SNPrintF) { char buffer[16]; |