Fix BIO_eof for BIO pairs

See uptream's 3105d695358d86c0f2a404b2b74a1870b941ce5e. Fleshed out
BIO pair tests to cover all these cases.

Change-Id: I5fd7f9c08c50b1462459c19a34230212b81cb674
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/78829
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
diff --git a/crypto/bio/bio_test.cc b/crypto/bio/bio_test.cc
index faeccd8..1935b6d 100644
--- a/crypto/bio/bio_test.cc
+++ b/crypto/bio/bio_test.cc
@@ -791,97 +791,134 @@
 class BIOPairTest : public testing::TestWithParam<bool> {};
 
 TEST_P(BIOPairTest, TestPair) {
-  BIO *bio1, *bio2;
-  ASSERT_TRUE(BIO_new_bio_pair(&bio1, 10, &bio2, 10));
-  bssl::UniquePtr<BIO> free_bio1(bio1), free_bio2(bio2);
+  BIO *bio1_raw, *bio2_raw;
+  ASSERT_TRUE(BIO_new_bio_pair(&bio1_raw, 10, &bio2_raw, 10));
+  bssl::UniquePtr<BIO> bio1(bio1_raw), bio2(bio2_raw);
 
   if (GetParam()) {
     std::swap(bio1, bio2);
   }
 
   // Check initial states.
-  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
-  EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
+  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1.get()));
+  EXPECT_FALSE(BIO_eof(bio1.get()));
+  EXPECT_EQ(0u, BIO_pending(bio1.get()));
+  EXPECT_EQ(0u, BIO_wpending(bio1.get()));
 
   // Data written in one end may be read out the other.
   uint8_t buf[20];
-  EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
-  EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
-  ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
+  EXPECT_EQ(5, BIO_write(bio1.get(), "12345", 5));
+  EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  EXPECT_EQ(5u, BIO_pending(bio2.get()));
+  EXPECT_EQ(5u, BIO_wpending(bio1.get()));
+  ASSERT_EQ(5, BIO_read(bio2.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
-  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  EXPECT_EQ(0u, BIO_pending(bio2.get()));
+  EXPECT_EQ(0u, BIO_wpending(bio1.get()));
 
   // Attempting to write more than 10 bytes will write partially.
-  EXPECT_EQ(10, BIO_write(bio1, "1234567890___", 13));
-  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
-  EXPECT_EQ(-1, BIO_write(bio1, "z", 1));
-  EXPECT_TRUE(BIO_should_write(bio1));
-  ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
+  EXPECT_EQ(10, BIO_write(bio1.get(), "1234567890___", 13));
+  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  EXPECT_EQ(-1, BIO_write(bio1.get(), "z", 1));
+  EXPECT_TRUE(BIO_should_write(bio1.get()));
+  ASSERT_EQ(10, BIO_read(bio2.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("1234567890"), Bytes(buf, 10));
-  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1.get()));
 
   // Unsuccessful reads update the read request.
-  EXPECT_EQ(-1, BIO_read(bio2, buf, 5));
-  EXPECT_TRUE(BIO_should_read(bio2));
-  EXPECT_EQ(5u, BIO_ctrl_get_read_request(bio1));
+  EXPECT_EQ(-1, BIO_read(bio2.get(), buf, 5));
+  EXPECT_TRUE(BIO_should_read(bio2.get()));
+  EXPECT_EQ(5u, BIO_ctrl_get_read_request(bio1.get()));
 
   // The read request is clamped to the size of the buffer.
-  EXPECT_EQ(-1, BIO_read(bio2, buf, 20));
-  EXPECT_TRUE(BIO_should_read(bio2));
-  EXPECT_EQ(10u, BIO_ctrl_get_read_request(bio1));
+  EXPECT_EQ(-1, BIO_read(bio2.get(), buf, 20));
+  EXPECT_TRUE(BIO_should_read(bio2.get()));
+  EXPECT_EQ(10u, BIO_ctrl_get_read_request(bio1.get()));
 
   // Data may be written and read in chunks.
-  EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
-  EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
-  EXPECT_EQ(5, BIO_write(bio1, "67890___", 8));
-  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
-  ASSERT_EQ(3, BIO_read(bio2, buf, 3));
+  EXPECT_EQ(5, BIO_write(bio1.get(), "12345", 5));
+  EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  EXPECT_EQ(5, BIO_write(bio1.get(), "67890___", 8));
+  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  ASSERT_EQ(3, BIO_read(bio2.get(), buf, 3));
   EXPECT_EQ(Bytes("123"), Bytes(buf, 3));
-  EXPECT_EQ(3u, BIO_ctrl_get_write_guarantee(bio1));
-  ASSERT_EQ(7, BIO_read(bio2, buf, sizeof(buf)));
+  EXPECT_EQ(3u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  ASSERT_EQ(7, BIO_read(bio2.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("4567890"), Bytes(buf, 7));
-  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1.get()));
 
   // Successful reads reset the read request.
-  EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
+  EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1.get()));
 
   // Test writes and reads starting in the middle of the ring buffer and
   // wrapping to front.
-  EXPECT_EQ(8, BIO_write(bio1, "abcdefgh", 8));
-  EXPECT_EQ(2u, BIO_ctrl_get_write_guarantee(bio1));
-  ASSERT_EQ(3, BIO_read(bio2, buf, 3));
+  EXPECT_EQ(8, BIO_write(bio1.get(), "abcdefgh", 8));
+  EXPECT_EQ(2u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  ASSERT_EQ(3, BIO_read(bio2.get(), buf, 3));
   EXPECT_EQ(Bytes("abc"), Bytes(buf, 3));
-  EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
-  EXPECT_EQ(5, BIO_write(bio1, "ijklm___", 8));
-  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
-  ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
+  EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  EXPECT_EQ(5, BIO_write(bio1.get(), "ijklm___", 8));
+  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  ASSERT_EQ(10, BIO_read(bio2.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("defghijklm"), Bytes(buf, 10));
-  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
+  EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1.get()));
 
   // Data may flow from both ends in parallel.
-  EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
-  EXPECT_EQ(5, BIO_write(bio2, "67890", 5));
-  ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
+  EXPECT_EQ(5, BIO_write(bio1.get(), "12345", 5));
+  EXPECT_EQ(5, BIO_write(bio2.get(), "67890", 5));
+  ASSERT_EQ(5, BIO_read(bio2.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
-  ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
+  ASSERT_EQ(5, BIO_read(bio1.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("67890"), Bytes(buf, 5));
 
   // Closing the write end causes an EOF on the read half, after draining.
-  EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
-  EXPECT_TRUE(BIO_shutdown_wr(bio1));
-  ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
+  EXPECT_EQ(5, BIO_write(bio1.get(), "12345", 5));
+  EXPECT_TRUE(BIO_shutdown_wr(bio1.get()));
+  EXPECT_FALSE(BIO_eof(bio2.get()));
+  EXPECT_EQ(5u, BIO_pending(bio2.get()));
+  EXPECT_EQ(5u, BIO_wpending(bio1.get()));
+  ASSERT_EQ(5, BIO_read(bio2.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
-  EXPECT_EQ(0, BIO_read(bio2, buf, sizeof(buf)));
+  EXPECT_TRUE(BIO_eof(bio2.get()));
+  EXPECT_EQ(0u, BIO_pending(bio2.get()));
+  EXPECT_EQ(0u, BIO_wpending(bio1.get()));
+  EXPECT_EQ(0, BIO_read(bio2.get(), buf, sizeof(buf)));
+  EXPECT_TRUE(BIO_eof(bio2.get()));
+  EXPECT_EQ(0u, BIO_pending(bio2.get()));
+  EXPECT_EQ(0u, BIO_wpending(bio1.get()));
 
   // A closed write end may not be written to.
-  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
-  EXPECT_EQ(-1, BIO_write(bio1, "_____", 5));
+  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1.get()));
+  EXPECT_EQ(-1, BIO_write(bio1.get(), "_____", 5));
   EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_BIO, BIO_R_BROKEN_PIPE));
 
   // The other end is still functional.
-  EXPECT_EQ(5, BIO_write(bio2, "12345", 5));
-  ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
+  EXPECT_EQ(5, BIO_write(bio2.get(), "12345", 5));
+  ASSERT_EQ(5, BIO_read(bio1.get(), buf, sizeof(buf)));
   EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
+  EXPECT_FALSE(BIO_eof(bio1.get()));
+
+  // Destroying |bio2| implicitly closes it, and discards unread data.
+  EXPECT_EQ(5, BIO_write(bio2.get(), "12345", 5));
+  bio2 = nullptr;
+
+  // |bio1| no longer has the "init" flag set, so reads and writes will fail at
+  // the BIO framework.
+  EXPECT_FALSE(BIO_get_init(bio1.get()));
+  EXPECT_EQ(-2, BIO_write(bio1.get(), "12345", 5));
+  EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_BIO, BIO_R_UNINITIALIZED));
+  EXPECT_EQ(-2, BIO_read(bio1.get(), buf, sizeof(buf)));
+  EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_BIO, BIO_R_UNINITIALIZED));
+
+  // Although in this disconnected state, |BIO_ctrl| works. |bio1| should
+  // report EOF when it has no peer.
+  EXPECT_TRUE(BIO_eof(bio1.get()));
+
+  // BIO_ctrl_get_write_guarantee should return 0 because there is no one to
+  // write to.
+  EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1.get()));
 }
 
 INSTANTIATE_TEST_SUITE_P(All, BIOPairTest, testing::Values(false, true));
diff --git a/crypto/bio/pair.cc b/crypto/bio/pair.cc
index ac5a9c5..c290332 100644
--- a/crypto/bio/pair.cc
+++ b/crypto/bio/pair.cc
@@ -381,12 +381,10 @@
       return 1;
 
     case BIO_CTRL_EOF: {
-      BIO *other_bio = reinterpret_cast<BIO *>(ptr);
-      if (other_bio) {
-        struct bio_bio_st *other_b =
-            reinterpret_cast<bio_bio_st *>(other_bio->ptr);
-        assert(other_b != nullptr);
-        return other_b->len == 0 && other_b->closed;
+      if (b->peer) {
+        auto *peer_b = reinterpret_cast<bio_bio_st *>(b->peer->ptr);
+        assert(peer_b != nullptr);
+        return peer_b->len == 0 && peer_b->closed;
       }
       return 1;
     }