Skip to content

Commit f35e3a4

Browse files
committed
http2: fix weight overflow in RFC 7540 write scheduler
We use uint8 (0-255, inclusive) to represent the RFC 7540 priorities weight (1-256, inclusive). To account for the difference, we add 1 to the uint8 weight value within sortPriorityNodeSiblingsRFC7540. However, the addition was done before converting the uint8 type to float. As a result, when provided a maximum weight value, overflow will happen and will cause the scheduler to treat the maximum weight as a minimum weight instead. This CL fixes the issue by making sure the addition happens after the type conversion. Change-Id: I404e87e5ad85fa06d5fa49cda613c93ac8847bdc Reviewed-on: https://go-review.googlesource.com/c/net/+/714742 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Nicholas Husin <[email protected]>
1 parent 89adc90 commit f35e3a4

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

http2/writesched_priority_rfc7540.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ func (z sortPriorityNodeSiblingsRFC7540) Swap(i, k int) { z[i], z[k] = z[k], z[i
214214
func (z sortPriorityNodeSiblingsRFC7540) Less(i, k int) bool {
215215
// Prefer the subtree that has sent fewer bytes relative to its weight.
216216
// See sections 5.3.2 and 5.3.4.
217-
wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
218-
wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
217+
wi, bi := float64(z[i].weight)+1, float64(z[i].subtreeBytes)
218+
wk, bk := float64(z[k].weight)+1, float64(z[k].subtreeBytes)
219219
if bi == 0 && bk == 0 {
220220
return wi >= wk
221221
}

http2/writesched_priority_rfc7540_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,39 @@ func TestPriorityWeights(t *testing.T) {
548548
}
549549
}
550550

551+
func TestPriorityWeightsMinMax(t *testing.T) {
552+
ws := defaultPriorityWriteScheduler()
553+
ws.OpenStream(1, OpenStreamOptions{})
554+
ws.OpenStream(2, OpenStreamOptions{})
555+
556+
sc := &serverConn{maxFrameSize: 8}
557+
st1 := &stream{id: 1, sc: sc}
558+
st2 := &stream{id: 2, sc: sc}
559+
st1.flow.add(40)
560+
st2.flow.add(40)
561+
562+
// st2 gets 256x the bandwidth of st1 (256 = (255+1)/(0+1)).
563+
// The maximum frame size is 8 bytes. The write sequence should be:
564+
// st2, total bytes so far is (st1=0, st=8)
565+
// st1, total bytes so far is (st1=8, st=8)
566+
// st2, total bytes so far is (st1=8, st=16)
567+
// st2, total bytes so far is (st1=8, st=24)
568+
// st2, total bytes so far is (st1=8, st=32)
569+
// st2, total bytes so far is (st1=8, st=40) // 5x bandwidth
570+
// st1, total bytes so far is (st1=16, st=40)
571+
// st1, total bytes so far is (st1=24, st=40)
572+
// st1, total bytes so far is (st1=32, st=40)
573+
// st1, total bytes so far is (st1=40, st=40)
574+
ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 40), false}, st1, nil})
575+
ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 40), false}, st2, nil})
576+
ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 0})
577+
ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 255})
578+
579+
if err := checkPopAll(ws, []uint32{2, 1, 2, 2, 2, 2, 1, 1, 1, 1}); err != nil {
580+
t.Error(err)
581+
}
582+
}
583+
551584
func TestPriorityRstStreamOnNonOpenStreams(t *testing.T) {
552585
ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{
553586
MaxClosedNodesInTree: 0,

0 commit comments

Comments
 (0)