Skip to content

Commit c8b7db0

Browse files
internal/zstd: configure window size for single segment frames
For #62513
1 parent 5e9afab commit c8b7db0

File tree

3 files changed

+46
-9
lines changed

3 files changed

+46
-9
lines changed
Binary file not shown.

src/internal/zstd/zstd.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,7 @@ retry:
235235
// Figure out the maximum amount of data we need to retain
236236
// for backreferences.
237237
var windowSize int
238-
if singleSegment {
239-
// No window required, as all the data is in a single buffer.
240-
windowSize = 0
241-
} else {
238+
if !singleSegment {
242239
// Window descriptor. RFC 3.1.1.1.2.
243240
windowDescriptor := r.scratch[0]
244241
exponent := uint64(windowDescriptor >> 3)
@@ -252,11 +249,6 @@ retry:
252249
if fuzzing && (windowLog > 31 || windowSize > 1<<27) {
253250
return r.makeError(relativeOffset, "windowSize too large")
254251
}
255-
256-
// RFC 8878 permits us to set an 8M max on window size.
257-
if windowSize > 8<<20 {
258-
windowSize = 8 << 20
259-
}
260252
}
261253

262254
// Frame_Content_Size. RFC 3.1.1.4.
@@ -278,6 +270,18 @@ retry:
278270
panic("unreachable")
279271
}
280272

273+
// RFC 3.1.1.1.2.
274+
// When Single_Segment_Flag is set, Window_Descriptor is not present.
275+
// In this case, Window_Size is Frame_Content_Size, which can be any value from 0 to 2^64 - 1 bytes (16 ExaBytes).
276+
if singleSegment {
277+
windowSize = int(r.remainingFrameSize)
278+
}
279+
280+
// RFC 8878 permits us to set an 8M max on window size.
281+
if windowSize > 8<<20 {
282+
windowSize = 8 << 20
283+
}
284+
281285
relativeOffset += headerSize
282286

283287
r.sawFrameHeader = true

src/internal/zstd/zstd_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package zstd
66

77
import (
88
"bytes"
9+
"crypto/sha256"
910
"fmt"
1011
"internal/race"
1112
"internal/testenv"
@@ -232,6 +233,38 @@ func TestAlloc(t *testing.T) {
232233
}
233234
}
234235

236+
func TestFileSamples(t *testing.T) {
237+
fixtures, err := os.ReadDir("testdata/")
238+
if err != nil {
239+
t.Fatal(err)
240+
}
241+
242+
for _, fixture := range fixtures {
243+
name := fixture.Name()
244+
if !strings.HasSuffix(name, ".zst") {
245+
continue
246+
}
247+
t.Run(name, func(t *testing.T) {
248+
f, err := os.Open("testdata/" + name)
249+
if err != nil {
250+
t.Fatal(err)
251+
}
252+
253+
r := NewReader(f)
254+
h := sha256.New()
255+
if _, err := io.Copy(h, r); err != nil {
256+
t.Fatal(err)
257+
}
258+
got := fmt.Sprintf("%x", h.Sum(nil))[:8]
259+
260+
want, _, _ := strings.Cut(name, ".")
261+
if got != want {
262+
t.Errorf("Wrong uncompressed content hash: want: %s, got: %s", want, got)
263+
}
264+
})
265+
}
266+
}
267+
235268
func BenchmarkLarge(b *testing.B) {
236269
b.StopTimer()
237270
b.ReportAllocs()

0 commit comments

Comments
 (0)