This is an automated email from the ASF dual-hosted git repository.

chenBright pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new 7c1b5225 Fix use-after-free of the new block in SingleIOBuf::assign 
(#3397)
7c1b5225 is described below

commit 7c1b52253911f4d7359ce2a3b34870d2bcccf714
Author: UB <[email protected]>
AuthorDate: Sun Jul 26 15:26:42 2026 +0530

    Fix use-after-free of the new block in SingleIOBuf::assign (#3397)
    
    Signed-off-by: ubeddulla khan <[email protected]>
---
 src/butil/single_iobuf.cpp |  8 +++++++-
 test/iobuf_unittest.cpp    | 28 ++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/src/butil/single_iobuf.cpp b/src/butil/single_iobuf.cpp
index 942c4ba9..7fc9bbcd 100644
--- a/src/butil/single_iobuf.cpp
+++ b/src/butil/single_iobuf.cpp
@@ -226,7 +226,13 @@ bool SingleIOBuf::assign(const IOBuf& buf, uint32_t 
msg_size) {
         if (!b) {
             return false;
         }
-        reset();
+        // Only drop the reference to the previously assigned data here.
+        // reset() would also release _cur_block, which alloc_block_by_size()
+        // has just set to `b', leaving `b' dangling.
+        if (_cur_ref.block != NULL) {
+            _cur_ref.block->dec_ref();
+            _cur_ref.block = NULL;
+        }
         char* out = b->data + b->size;
         const size_t nref = buf.backing_block_num();
         uint32_t last_len = msg_size;
diff --git a/test/iobuf_unittest.cpp b/test/iobuf_unittest.cpp
index 18d312eb..ddd5b599 100644
--- a/test/iobuf_unittest.cpp
+++ b/test/iobuf_unittest.cpp
@@ -1952,6 +1952,34 @@ TEST_F(IOBufTest, single_iobuf) {
     ASSERT_TRUE(p != nullptr);
 }
 
+TEST_F(IOBufTest, single_iobuf_assign_large_multi_block) {
+    // The message spans more than one BlockRef of the source IOBuf and does
+    // not fit in a default-sized block, so assign() has to concatenate it
+    // into a dedicated block.
+    const uint32_t n1 = 5000;
+    const uint32_t n2 = 6000;
+    char* d1 = (char*)malloc(n1);
+    memset(d1, 'a', n1);
+    char* d2 = (char*)malloc(n2);
+    memset(d2, 'b', n2);
+    butil::IOBuf buf;
+    buf.append_user_data(d1, n1, NULL);
+    buf.append_user_data(d2, n2, NULL);
+    ASSERT_EQ(2, buf.backing_block_num());
+
+    butil::SingleIOBuf sbuf;
+    ASSERT_TRUE(sbuf.assign(buf, n1 + n2));
+    ASSERT_EQ(n1 + n2, sbuf.get_length());
+    ASSERT_EQ(std::string(n1, 'a') + std::string(n2, 'b'),
+              std::string((const char*)sbuf.get_begin(), n1 + n2));
+
+    // Assigning again on top of an already assigned SingleIOBuf.
+    ASSERT_TRUE(sbuf.assign(buf, n1 + n2));
+    ASSERT_EQ(n1 + n2, sbuf.get_length());
+    ASSERT_EQ(std::string(n1, 'a') + std::string(n2, 'b'),
+              std::string((const char*)sbuf.get_begin(), n1 + n2));
+}
+
 TEST_F(IOBufTest, as_input_stream_basic) {
     butil::IOBuf buf;
     buf.append("hello world");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to