Merge pull request #123620 from benluddy/json-frame-reader-underlying-array-reuse
Remove shared ref to underlying array of JSONFrameReader's Read arg.
This commit is contained in:
		@@ -147,7 +147,6 @@ func (r *jsonFrameReader) Read(data []byte) (int, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// RawMessage#Unmarshal appends to data - we reset the slice down to 0 and will either see
 | 
						// RawMessage#Unmarshal appends to data - we reset the slice down to 0 and will either see
 | 
				
			||||||
	// data written to data, or be larger than data and a different array.
 | 
						// data written to data, or be larger than data and a different array.
 | 
				
			||||||
	n := len(data)
 | 
					 | 
				
			||||||
	m := json.RawMessage(data[:0])
 | 
						m := json.RawMessage(data[:0])
 | 
				
			||||||
	if err := r.decoder.Decode(&m); err != nil {
 | 
						if err := r.decoder.Decode(&m); err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
@@ -156,12 +155,19 @@ func (r *jsonFrameReader) Read(data []byte) (int, error) {
 | 
				
			|||||||
	// If capacity of data is less than length of the message, decoder will allocate a new slice
 | 
						// If capacity of data is less than length of the message, decoder will allocate a new slice
 | 
				
			||||||
	// and set m to it, which means we need to copy the partial result back into data and preserve
 | 
						// and set m to it, which means we need to copy the partial result back into data and preserve
 | 
				
			||||||
	// the remaining result for subsequent reads.
 | 
						// the remaining result for subsequent reads.
 | 
				
			||||||
	if len(m) > n {
 | 
						if len(m) > cap(data) {
 | 
				
			||||||
		//nolint:staticcheck // SA4006,SA4010 underlying array of data is modified here.
 | 
							copy(data, m)
 | 
				
			||||||
		data = append(data[0:0], m[:n]...)
 | 
							r.remaining = m[len(data):]
 | 
				
			||||||
		r.remaining = m[n:]
 | 
							return len(data), io.ErrShortBuffer
 | 
				
			||||||
		return n, io.ErrShortBuffer
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(m) > len(data) {
 | 
				
			||||||
 | 
							// The bytes beyond len(data) were stored in data's underlying array, which we do
 | 
				
			||||||
 | 
							// not own after this function returns.
 | 
				
			||||||
 | 
							r.remaining = append([]byte(nil), m[len(data):]...)
 | 
				
			||||||
 | 
							return len(data), io.ErrShortBuffer
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return len(m), nil
 | 
						return len(m), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package framer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -173,3 +174,17 @@ func TestJSONFrameReaderShortBuffer(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("unexpected: %v %d %q", err, n, buf)
 | 
							t.Fatalf("unexpected: %v %d %q", err, n, buf)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestJSONFrameReaderShortBufferNoUnderlyingArrayReuse(t *testing.T) {
 | 
				
			||||||
 | 
						b := bytes.NewBufferString("{}")
 | 
				
			||||||
 | 
						r := NewJSONFramedReader(io.NopCloser(b))
 | 
				
			||||||
 | 
						buf := make([]byte, 1, 2) // cap(buf) > len(buf) && cap(buf) <= len("{}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if n, err := r.Read(buf); !errors.Is(err, io.ErrShortBuffer) || n != 1 || string(buf[:n]) != "{" {
 | 
				
			||||||
 | 
							t.Fatalf("unexpected: %v %d %q", err, n, buf)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf = append(buf, make([]byte, 1)...) // stomps the second byte of the backing array
 | 
				
			||||||
 | 
						if n, err := r.Read(buf[1:]); err != nil || n != 1 || string(buf[1:1+n]) != "}" {
 | 
				
			||||||
 | 
							t.Fatalf("unexpected: %v %d %q", err, n, buf)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user