Skip to content

Commit ad8140e

Browse files
committed
quic: fix buffer slicing when handling overlapping stream data
When processing a STREAM frame that overlaps with already received data, our slicing calculation is wrong. As a result, upon receiving duplicate data, such as when packets are retransmitted, we end up writing the same data multiple times rather than deduplicating them. This seems to have resulted in spurious FINAL_SIZE_ERROR in our tests. For golang/go#78737 Change-Id: I0c6d34d7f7f376310dad43983cbdf32b6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/net/+/776080 Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Nicholas Husin <husin@google.com>
1 parent 23ee2ef commit ad8140e

2 files changed

Lines changed: 59 additions & 37 deletions

File tree

quic/stream.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ func (s *Stream) handleData(off int64, b []byte, fin bool) error {
815815
// sending us different data than we received the first time.
816816
// We currently don't bother.)
817817
newOff := min(end, s.inset[0].end)
818-
b = b[end-newOff:]
818+
b = b[newOff-off:]
819819
off = newOff
820820
}
821821
s.in.writeAt(b, off)

quic/stream_test.go

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -395,48 +395,70 @@ func TestStreamReceive(t *testing.T) {
395395
wantEOF: true,
396396
}},
397397
}} {
398-
testStreamTypesSynctest(t, test.name, func(t *testing.T, styp streamType) {
399-
tc := newTestConn(t, serverSide)
400-
tc.handshake()
401-
sid := newStreamID(clientSide, styp, 0)
402-
var s *Stream
403-
got := make([]byte, len(want))
404-
var total int
405-
for _, f := range test.frames {
406-
t.Logf("receive [%v,%v)", f.start, f.end)
407-
tc.writeFrames(packetType1RTT, debugFrameStream{
408-
id: sid,
409-
off: f.start,
410-
data: want[f.start:f.end],
411-
fin: f.fin,
412-
})
413-
if s == nil {
414-
s = tc.acceptStream()
415-
}
416-
for {
417-
n, err := s.Read(got[total:])
418-
t.Logf("s.Read() = %v, %v", n, err)
419-
total += n
420-
if f.wantEOF && err != io.EOF {
421-
t.Fatalf("Read() error = %v; want io.EOF", err)
398+
for _, buffered := range []bool{true, false} {
399+
name := test.name
400+
if buffered {
401+
name += "/buffered"
402+
} else {
403+
name += "/unbuffered"
404+
}
405+
testStreamTypesSynctest(t, name, func(t *testing.T, styp streamType) {
406+
tc := newTestConn(t, serverSide)
407+
tc.handshake()
408+
sid := newStreamID(clientSide, styp, 0)
409+
var s *Stream
410+
got := make([]byte, len(want))
411+
var total int
412+
413+
// readAndVerify reads all the data that has been buffered in s
414+
// so far, and verifies whether it contains the expected bytes
415+
// and EOF.
416+
readAndVerify := func(wantEOF bool, wantTotal int) {
417+
for {
418+
n, err := s.Read(got[total:])
419+
t.Logf("s.Read() = %v, %v", n, err)
420+
total += n
421+
if wantEOF && err != io.EOF {
422+
t.Fatalf("Read() error = %v; want io.EOF", err)
423+
}
424+
if !wantEOF && err == io.EOF {
425+
t.Fatalf("Read() error = io.EOF, want something else")
426+
}
427+
if err != nil {
428+
break
429+
}
422430
}
423-
if !f.wantEOF && err == io.EOF {
424-
t.Fatalf("Read() error = io.EOF, want something else")
431+
if total != wantTotal {
432+
t.Fatalf("total bytes read = %v, want %v", total, wantTotal)
425433
}
426-
if err != nil {
427-
break
434+
for i := 0; i < total; i++ {
435+
if got[i] != want[i] {
436+
t.Fatalf("byte %v differs: got %v, want %v", i, got[i], want[i])
437+
}
428438
}
429439
}
430-
if total != f.want {
431-
t.Fatalf("total bytes read = %v, want %v", total, f.want)
432-
}
433-
for i := 0; i < total; i++ {
434-
if got[i] != want[i] {
435-
t.Fatalf("byte %v differs: got %v, want %v", i, got[i], want[i])
440+
441+
for _, f := range test.frames {
442+
t.Logf("receive [%v,%v)", f.start, f.end)
443+
tc.writeFrames(packetType1RTT, debugFrameStream{
444+
id: sid,
445+
off: f.start,
446+
data: want[f.start:f.end],
447+
fin: f.fin,
448+
})
449+
if s == nil {
450+
s = tc.acceptStream()
451+
}
452+
if !buffered {
453+
readAndVerify(f.wantEOF, f.want)
436454
}
437455
}
438-
}
439-
})
456+
if buffered {
457+
finalFrame := test.frames[len(test.frames)-1]
458+
readAndVerify(finalFrame.wantEOF, finalFrame.want)
459+
}
460+
})
461+
}
440462
}
441463

442464
}

0 commit comments

Comments
 (0)