Avoid another NULL+0 in BIO_s_mem

That NULL+0 is forbidden is still an awful language bug in C (fixed in
C++), but this particular instance could have been written without
pointer arithmetic. While I'm here, tidy pointers a bit:

- No need to cast pointers to char* when we're writing to void* anyway

- BIO_C_GET_BUF_MEM_PTR is technically a strict aliasing violation. The
  pointer points to a BUF_MEM*, not a char*, so we should not write to
  it as a char**.

- C casts from void* freely and we've usually omitted the cast in that
  case. (Though if we ever move libcrypto to C++, that'll all have to
  change.)

Bug: b:286384999
Change-Id: I16d7da675d61f726f259fc9a3cc4a6fce2d6d1fd
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/60605
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
diff --git a/crypto/bio/bio_mem.c b/crypto/bio/bio_mem.c
index 1ee148b..5d7534c 100644
--- a/crypto/bio/bio_mem.c
+++ b/crypto/bio/bio_mem.c
@@ -206,7 +206,6 @@
 
 static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
   long ret = 1;
-  char **pptr;
 
   BUF_MEM *b = (BUF_MEM *)bio->ptr;
 
@@ -232,8 +231,8 @@
     case BIO_CTRL_INFO:
       ret = (long)b->length;
       if (ptr != NULL) {
-        pptr = (char **)ptr;
-        *pptr = (char *)&b->data[0];
+        char **pptr = ptr;
+        *pptr = b->data;
       }
       break;
     case BIO_C_SET_BUF_MEM:
@@ -243,8 +242,8 @@
       break;
     case BIO_C_GET_BUF_MEM_PTR:
       if (ptr != NULL) {
-        pptr = (char **)ptr;
-        *pptr = (char *)b;
+        BUF_MEM **pptr = ptr;
+        *pptr = b;
       }
       break;
     case BIO_CTRL_GET_CLOSE:
@@ -294,15 +293,15 @@
 }
 
 long BIO_get_mem_data(BIO *bio, char **contents) {
-  return BIO_ctrl(bio, BIO_CTRL_INFO, 0, (char *) contents);
+  return BIO_ctrl(bio, BIO_CTRL_INFO, 0, contents);
 }
 
 int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) {
-  return (int)BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, (char *) out);
+  return (int)BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, out);
 }
 
 int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) {
-  return (int)BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, (char *) b);
+  return (int)BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, b);
 }
 
 int BIO_set_mem_eof_return(BIO *bio, int eof_value) {
diff --git a/crypto/bio/bio_test.cc b/crypto/bio/bio_test.cc
index 6610be9..8827ce6 100644
--- a/crypto/bio/bio_test.cc
+++ b/crypto/bio/bio_test.cc
@@ -287,11 +287,24 @@
   bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
   ASSERT_TRUE(bio);
 
+  auto check_bio_contents = [&](Bytes b) {
+    const uint8_t *contents;
+    size_t len;
+    ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
+    EXPECT_EQ(Bytes(contents, len), b);
+
+    char *contents_c;
+    long len_l = BIO_get_mem_data(bio.get(), &contents_c);
+    ASSERT_GE(len_l, 0);
+    EXPECT_EQ(Bytes(contents_c, len_l), b);
+
+    BUF_MEM *buf;
+    ASSERT_EQ(BIO_get_mem_ptr(bio.get(), &buf), 1);
+    EXPECT_EQ(Bytes(buf->data, buf->length), b);
+  };
+
   // It is initially empty.
-  const uint8_t *contents;
-  size_t len;
-  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
-  EXPECT_EQ(Bytes(contents, len), Bytes(""));
+  check_bio_contents(Bytes(""));
   EXPECT_EQ(BIO_eof(bio.get()), 1);
 
   // Reading from it should default to returning a retryable error.
@@ -310,44 +323,38 @@
 
   // Writes append to the buffer.
   ASSERT_EQ(BIO_write(bio.get(), "abcdef", 6), 6);
-  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
-  EXPECT_EQ(Bytes(contents, len), Bytes("abcdef"));
+  check_bio_contents(Bytes("abcdef"));
   EXPECT_EQ(BIO_eof(bio.get()), 0);
 
   // Writes can include embedded NULs.
   ASSERT_EQ(BIO_write(bio.get(), "\0ghijk", 6), 6);
-  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
-  EXPECT_EQ(Bytes(contents, len), Bytes("abcdef\0ghijk", 12));
+  check_bio_contents(Bytes("abcdef\0ghijk", 12));
   EXPECT_EQ(BIO_eof(bio.get()), 0);
 
   // Do a partial read.
   int ret = BIO_read(bio.get(), buf, 4);
   ASSERT_GT(ret, 0);
   EXPECT_EQ(Bytes(buf, ret), Bytes("abcd"));
-  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
-  EXPECT_EQ(Bytes(contents, len), Bytes("ef\0ghijk", 8));
+  check_bio_contents(Bytes("ef\0ghijk", 8));
   EXPECT_EQ(BIO_eof(bio.get()), 0);
 
   // Reads and writes may alternate.
   ASSERT_EQ(BIO_write(bio.get(), "lmnopq", 6), 6);
-  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
-  EXPECT_EQ(Bytes(contents, len), Bytes("ef\0ghijklmnopq", 14));
+  check_bio_contents(Bytes("ef\0ghijklmnopq", 14));
   EXPECT_EQ(BIO_eof(bio.get()), 0);
 
   // Reads may consume embedded NULs.
   ret = BIO_read(bio.get(), buf, 4);
   ASSERT_GT(ret, 0);
   EXPECT_EQ(Bytes(buf, ret), Bytes("ef\0g", 4));
-  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
-  EXPECT_EQ(Bytes(contents, len), Bytes("hijklmnopq"));
+  check_bio_contents(Bytes("hijklmnopq"));
   EXPECT_EQ(BIO_eof(bio.get()), 0);
 
   // The read buffer exceeds the |BIO|, so we consume everything.
   ret = BIO_read(bio.get(), buf, sizeof(buf));
   ASSERT_GT(ret, 0);
   EXPECT_EQ(Bytes(buf, ret), Bytes("hijklmnopq"));
-  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
-  EXPECT_EQ(Bytes(contents, len), Bytes(""));
+  check_bio_contents(Bytes(""));
   EXPECT_EQ(BIO_eof(bio.get()), 1);
 
   // The |BIO| is now empty.