[ubsan] Fix some UBSAN warnings

Passing nullptr to memset/memcpy is UB, even if the size passed in is 0.
Avoid making such calls when we don't yet have a buffer to write into.

Avoid possible signed integer overflow.

This is basically a cherry-pick of
https://github.com/protocolbuffers/protobuf/commit/d14cacd791ac553b5dfba5f303fc631b42f6e662
and
https://github.com/protocolbuffers/protobuf/commit/0f8e6d1402fc021e02b9def83df9a9683ba6ea76

Change-Id: I286e90dd247c25cf4757cbf4bc92ab578b5d7bdb
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/protobuf/+/426575
Reviewed-by: Roland McGrath <mcgrathr@google.com>
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index 8493268..992ef84 100644
--- a/src/google/protobuf/io/printer.cc
+++ b/src/google/protobuf/io/printer.cc
@@ -350,10 +350,12 @@
   while (size > buffer_size_) {
     // Data exceeds space in the buffer.  Copy what we can and request a
     // new buffer.
-    memcpy(buffer_, data, buffer_size_);
-    offset_ += buffer_size_;
-    data += buffer_size_;
-    size -= buffer_size_;
+    if (buffer_) {
+      memcpy(buffer_, data, buffer_size_);
+      offset_ += buffer_size_;
+      data += buffer_size_;
+      size -= buffer_size_;
+    }
     void* void_buffer;
     failed_ = !output_->Next(&void_buffer, &buffer_size_);
     if (failed_) return;
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index 1a4d71c..9858375 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -1114,10 +1114,12 @@
 }
 
 char* FastInt64ToBufferLeft(int64 i, char* buffer) {
-  uint64 u = i;
+  uint64 u = 0;
   if (i < 0) {
     *buffer++ = '-';
-    u = -i;
+    u -= i;
+  } else {
+    u = i;
   }
   return FastUInt64ToBufferLeft(u, buffer);
 }
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index eed2a76..a0df094 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -1269,8 +1269,10 @@
     while (size > buffer_size_) {
       // Data exceeds space in the buffer. Write what we can and request a new
       // buffer.
-      memset(buffer_, ' ', buffer_size_);
-      size -= buffer_size_;
+      if (buffer_size_ > 0) {
+        memset(buffer_, ' ', buffer_size_);
+        size -= buffer_size_;
+      }
       void* void_buffer;
       failed_ = !output_->Next(&void_buffer, &buffer_size_);
       if (failed_) return;