Fix BIO_printf crash on Mac.

A single va_list may not be used twice. Nothing calls BIO_vprintf and it just
(v)snprintfs into a buffer anyway, so remove it. If it's actually needed, we
can fiddle with va_copy and the lack of it in C89 later, but anything that
actually cares can just assemble the output externally.

Add a test in bio_test.c.

BUG=399546

Change-Id: Ia40a68b31cb5984d817e9c55351f49d9d6c964c1
Reviewed-on: https://boringssl-review.googlesource.com/1391
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/bio/printf.c b/crypto/bio/printf.c
index 7f7106f..daebe74 100644
--- a/crypto/bio/printf.c
+++ b/crypto/bio/printf.c
@@ -66,38 +66,30 @@
 
 #include <openssl/mem.h>
 
-
 int BIO_printf(BIO *bio, const char *format, ...) {
   va_list args;
-  int ret;
-
-  va_start(args, format);
-
-  ret = BIO_vprintf(bio, format, args);
-
-  va_end(args);
-  return ret;
-}
-
-int BIO_vprintf(BIO *bio, const char *format, va_list args) {
   char buf[256], *out, out_malloced = 0;
   int out_len, ret;
 
-  /* Note: this is assuming that va_list is ok to copy as POD. If the system
-   * defines it with a pointer to mutable state then passing it twice to
-   * vsnprintf will not work. */
+  va_start(args, format);
   out_len = vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+
   if (out_len >= sizeof(buf)) {
     const int requested_len = out_len;
-    /* The output was truncated. */
-    out = OPENSSL_malloc(requested_len);
+    /* The output was truncated. Note that vsnprintf's return value
+     * does not include a trailing NUL, but the buffer must be sized
+     * for it. */
+    out = OPENSSL_malloc(requested_len + 1);
     out_malloced = 1;
     if (out == NULL) {
       /* Unclear what can be done in this situation. OpenSSL has historically
        * crashed and that seems better than producing the wrong output. */
       abort();
     }
-    out_len = vsnprintf(out, requested_len, format, args);
+    va_start(args, format);
+    out_len = vsnprintf(out, requested_len + 1, format, args);
+    va_end(args);
     assert(out_len == requested_len);
   } else {
     out = buf;