Refactor BufferOutputStream.

- Rewrite BufferOutputStream to handle 0 sized buffers and to get rid
  of an unnecessary loop.
- Add tests to verify overflow corner cases.
- Implement async_safe_format_buffer to call async_safe_format_buffer_va_list
  instead of duplicate the code.

Test: Ran new unit tests, booted on angler.
Change-Id: I7fb13e209f5b7443d212f55aab4b05ff2e0e8219
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 99ff0c7..d81ef34 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -60,43 +60,36 @@
 
 struct BufferOutputStream {
  public:
-  BufferOutputStream(char* buffer, size_t size) : total(0) {
-    buffer_ = buffer;
-    end_ = buffer + size - 1;
-    pos_ = buffer_;
-    pos_[0] = '\0';
+  BufferOutputStream(char* buffer, size_t size) : total(0), pos_(buffer), avail_(size) {
+    if (avail_ > 0) pos_[0] = '\0';
   }
-
-  ~BufferOutputStream() {}
+  ~BufferOutputStream() = default;
 
   void Send(const char* data, int len) {
     if (len < 0) {
       len = strlen(data);
     }
-
     total += len;
 
-    while (len > 0) {
-      int avail = end_ - pos_;
-      if (avail == 0) {
-        return;
-      }
-      if (avail > len) {
-        avail = len;
-      }
-      memcpy(pos_, data, avail);
-      pos_ += avail;
-      pos_[0] = '\0';
-      len -= avail;
+    if (avail_ <= 1) {
+      // No space to put anything else.
+      return;
     }
+
+    if (static_cast<size_t>(len) >= avail_) {
+      len = avail_ - 1;
+    }
+    memcpy(pos_, data, len);
+    pos_ += len;
+    pos_[0] = '\0';
+    avail_ -= len;
   }
 
   size_t total;
 
  private:
-  char* buffer_;
   char* pos_;
-  char* end_;
+  size_t avail_;
 };
 
 struct FdOutputStream {
@@ -107,16 +100,15 @@
     if (len < 0) {
       len = strlen(data);
     }
-
     total += len;
 
     while (len > 0) {
-      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
-      if (rc == -1) {
+      ssize_t bytes = TEMP_FAILURE_RETRY(write(fd_, data, len));
+      if (bytes == -1) {
         return;
       }
-      data += rc;
-      len -= rc;
+      data += bytes;
+      len -= bytes;
     }
   }
 
@@ -409,15 +401,6 @@
   }
 }
 
-int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
-  BufferOutputStream os(buffer, buffer_size);
-  va_list args;
-  va_start(args, format);
-  out_vformat(os, format, args);
-  va_end(args);
-  return os.total;
-}
-
 int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
                                      va_list args) {
   BufferOutputStream os(buffer, buffer_size);
@@ -425,6 +408,14 @@
   return os.total;
 }
 
+int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int buffer_len = async_safe_format_buffer_va_list(buffer, buffer_size, format, args);
+  va_end(args);
+  return buffer_len;
+}
+
 int async_safe_format_fd(int fd, const char* format, ...) {
   FdOutputStream os(fd);
   va_list args;