about summary refs log tree commit diff
path: root/absl/strings/internal/str_format/output.cc
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2018-10-24T01·09-0700
committerAshley Hedberg <ahedberg@google.com>2018-10-24T20·47-0400
commit94c298e2a0ae409e283cab96c954a685bd865a70 (patch)
tree61581c5b86e25d374cf6abb2ae11e8850367ffe8 /absl/strings/internal/str_format/output.cc
parent8efc52608700647d7bd5ef55ef2487af1ecdaa7c (diff)
Export of internal Abseil changes.
--
441d1aa02483cdc510eb2fef012b31384fd8e3a6 by Eric Fiselier <ericwf@google.com>:

Fix str_format with non-POSIX libc implementations.

PiperOrigin-RevId: 218441122

--
da6190130e74222af6eb161a5593364341370370 by Jon Cohen <cohenjon@google.com>:

Refactor ExceptionSafetyTester::Test in order to remove the levels of indirection related to unpacking tuples.

PiperOrigin-RevId: 218403355
GitOrigin-RevId: 441d1aa02483cdc510eb2fef012b31384fd8e3a6
Change-Id: I6f6b978eb96fe261e8ee41ecdce185e5356a601d
Diffstat (limited to 'absl/strings/internal/str_format/output.cc')
-rw-r--r--absl/strings/internal/str_format/output.cc27
1 files changed, 25 insertions, 2 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;
       }
     }
   }