boundedSnappyDecode decodes xerial/snappy into a capped buffer grown on demand up to limit. DecodeCapped returns ErrDstTooSmall rather than writing past the buffer's capacity, which we translate into a too-large error once the buffer reaches limit. A non-positive limit decodes in one shot, unbounded
(cc CompressionCodec, data []byte, limit int)
| 71 | // past the buffer's capacity, which we translate into a too-large error once |
| 72 | // the buffer reaches limit. A non-positive limit decodes in one shot, unbounded. |
| 73 | func boundedSnappyDecode(cc CompressionCodec, data []byte, limit int) ([]byte, error) { |
| 74 | if limit <= 0 { |
| 75 | return snappy.Decode(data) |
| 76 | } |
| 77 | |
| 78 | bufp := bytesPool.Get().(*[]byte) |
| 79 | buf := *bufp |
| 80 | defer func() { |
| 81 | *bufp = buf[:0] |
| 82 | bytesPool.Put(bufp) |
| 83 | }() |
| 84 | |
| 85 | size := max(cap(buf), 1024) |
| 86 | var out []byte |
| 87 | var err error |
| 88 | for { |
| 89 | if size > limit { |
| 90 | size = limit |
| 91 | } |
| 92 | if cap(buf) < size { |
| 93 | buf = make([]byte, 0, size) |
| 94 | } |
| 95 | out, err = snappy.DecodeCapped(buf[:0:size], data) |
| 96 | if !errors.Is(err, snappy.ErrDstTooSmall) || size >= limit { |
| 97 | break |
| 98 | } |
| 99 | size *= 2 |
| 100 | } |
| 101 | |
| 102 | switch { |
| 103 | case errors.Is(err, snappy.ErrDstTooSmall): |
| 104 | return nil, newDecompressedBatchTooLargeError(cc, limit) |
| 105 | case err != nil: |
| 106 | return nil, err |
| 107 | default: |
| 108 | return slices.Clone(out), nil |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // boundedZstdDecode decodes into a pooled buffer using a decoder whose max |
| 113 | // memory is capped at limit, so an oversized frame fails without allocating its |
no test coverage detected