Fix size_t truncations in bio_mem.c

The outl <= 0, etc., checks are actually redundant with logic in the
wrappers, but it seems easier to just add the check and avoid worrying
about it. Maybe someday we'll make the internals use size_t and this
will be moot.

Bug: 516
Change-Id: I0bea5ac325c79b9765d822c816661fe4f2bcd4cc
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58546
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/bio/bio_mem.c b/crypto/bio/bio_mem.c
index b483989..1ee148b 100644
--- a/crypto/bio/bio_mem.c
+++ b/crypto/bio/bio_mem.c
@@ -130,13 +130,15 @@
 }
 
 static int mem_read(BIO *bio, char *out, int outl) {
-  int ret;
-  BUF_MEM *b = (BUF_MEM*) bio->ptr;
-
   BIO_clear_retry_flags(bio);
-  ret = outl;
-  if (b->length < INT_MAX && ret > (int)b->length) {
-    ret = b->length;
+  if (outl <= 0) {
+    return 0;
+  }
+
+  BUF_MEM *b = bio->ptr;
+  int ret = outl;
+  if ((size_t)ret > b->length) {
+    ret = (int)b->length;
   }
 
   if (ret > 0) {
@@ -157,65 +159,49 @@
 }
 
 static int mem_write(BIO *bio, const char *in, int inl) {
-  int ret = -1;
-  int blen;
-  BUF_MEM *b;
-
-  b = (BUF_MEM *)bio->ptr;
+  BIO_clear_retry_flags(bio);
+  if (inl <= 0) {
+    return 0;  // Successfully write zero bytes.
+  }
 
   if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
     OPENSSL_PUT_ERROR(BIO, BIO_R_WRITE_TO_READ_ONLY_BIO);
-    goto err;
+    return -1;
   }
 
-  BIO_clear_retry_flags(bio);
-  blen = b->length;
-  if (INT_MAX - blen < inl) {
-    goto err;
+  BUF_MEM *b = bio->ptr;
+  if (!BUF_MEM_append(b, in, inl)) {
+    return -1;
   }
-  if (BUF_MEM_grow_clean(b, blen + inl) != ((size_t) blen) + inl) {
-    goto err;
-  }
-  OPENSSL_memcpy(&b->data[blen], in, inl);
-  ret = inl;
 
-err:
-  return ret;
+  return inl;
 }
 
 static int mem_gets(BIO *bio, char *buf, int size) {
-  int i, j;
-  char *p;
-  BUF_MEM *b = (BUF_MEM *)bio->ptr;
-
   BIO_clear_retry_flags(bio);
-  j = b->length;
-  if (size - 1 < j) {
-    j = size - 1;
-  }
-  if (j <= 0) {
-    if (size > 0) {
-      *buf = 0;
-    }
+  if (size <= 0) {
     return 0;
   }
 
-  p = b->data;
-  for (i = 0; i < j; i++) {
-    if (p[i] == '\n') {
-      i++;
-      break;
-    }
+  // The buffer size includes space for the trailing NUL, so we can read at most
+  // one fewer byte.
+  BUF_MEM *b = bio->ptr;
+  int ret = size - 1;
+  if ((size_t)ret > b->length) {
+    ret = (int)b->length;
   }
 
-  // i is now the max num of bytes to copy, either j or up to and including the
-  // first newline
-
-  i = mem_read(bio, buf, i);
-  if (i > 0) {
-    buf[i] = '\0';
+  // Stop at the first newline.
+  const char *newline = OPENSSL_memchr(b->data, '\n', ret);
+  if (newline != NULL) {
+    ret = (int)(newline - b->data + 1);
   }
-  return i;
+
+  ret = mem_read(bio, buf, ret);
+  if (ret >= 0) {
+    buf[ret] = '\0';
+  }
+  return ret;
 }
 
 static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {