From 7efa16d55d5cedae5871ce59b9c285f7f390b957 Mon Sep 17 00:00:00 2001
From: Jean Boussier <jean.boussier@gmail.com>
Date: Wed, 7 Dec 2022 16:37:09 +0100
Subject: [PATCH] Undo BufferedIO#rbuf_consume_all_shareable! optimization

This optimization is unsafe because `dest` is allowed to be a custom
object responding to `<<` (e.g. a block wrapped in `ReadAdapter`).

So the receiver can hold onto the passed buffer for as long as it wants.

If it was guaranteed that `ReadAdapter` was the only possible receiver
we could dup the buffer there for mutation safety, but I'm not certain
it's the case so I'd rather err on the safe side.

Ref: https://github.com/shrinerb/shrine/issues/610
---
 lib/net/protocol.rb | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index aba6557..728cc19 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -157,7 +157,7 @@ def read(len, dest = ''.b, ignore_eof = false)
       read_bytes = 0
       begin
         while read_bytes + rbuf_size < len
-          if s = rbuf_consume_all_shareable!
+          if s = rbuf_consume_all
             read_bytes += s.bytesize
             dest << s
           end
@@ -178,7 +178,7 @@ def read_all(dest = ''.b)
       read_bytes = 0
       begin
         while true
-          if s = rbuf_consume_all_shareable!
+          if s = rbuf_consume_all
             read_bytes += s.bytesize
             dest << s
           end
@@ -250,18 +250,8 @@ def rbuf_size
       @rbuf.bytesize - @rbuf_offset
     end
 
-    # Warning: this method may share the buffer to avoid
-    # copying. The caller must no longer use the returned
-    # string once rbuf_fill has been called again
-    def rbuf_consume_all_shareable!
-      @rbuf_empty = true
-      buf = if @rbuf_offset == 0
-        @rbuf
-      else
-        @rbuf.byteslice(@rbuf_offset..-1)
-      end
-      @rbuf_offset = @rbuf.bytesize
-      buf
+    def rbuf_consume_all
+      rbuf_consume if rbuf_size > 0
     end
 
     def rbuf_consume(len = nil)