[
https://issues.apache.org/jira/browse/AVRO-4290?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18102690#comment-18102690
]
ASF subversion and git services commented on AVRO-4290:
-------------------------------------------------------
Commit c50ffa586a7a2f60fe8ed05489d4c7d3a578e092 in avro's branch
refs/heads/main from Ismaël Mejía
[ https://gitbox.apache.org/repos/asf?p=avro.git;h=c50ffa586a ]
AVRO-4290: [python] Enforce a maximum decompressed block size (#3850)
* AVRO-4290: [python] Enforce a maximum decompressed block size
When reading a data file, each block is decompressed according to the
file's codec. A block with a very high compression ratio (or a malformed
block) could expand to far more memory than its compressed size. Enforce a
configurable maximum decompressed size across the deflate, bzip2, snappy and
zstandard codecs, mirroring the Java SDK's decompression limit (AVRO-4247).
The limit defaults to 200 MiB and can be overridden with the
AVRO_MAX_DECOMPRESS_LENGTH environment variable; exceeding it raises
AvroDecompressionSizeException.
Assisted-by: GitHub Copilot:claude-opus-4.8
* AVRO-4290: [python] Address review: avoid deflate copy; zstd
check-before-extend
- DeflateCodec.decompress accumulates into a bytearray so the flush() output is
appended in place instead of creating an extra full-size copy of the already
decompressed data.
- ZstandardCodec.decompress checks len(uncompressed) + len(chunk) before
extending, so the buffer never grows past the configured limit.
Assisted-by: GitHub Copilot:claude-opus-4.8
* AVRO-4290: [python] Verify bzip2 stream EOF and drain fully
BZip2Codec.decompress now loops the BZ2Decompressor: it drains all buffered
output (bounded by the limit), verifies the stream reached EOF (rejecting a
truncated/corrupt block with InvalidAvroBinaryEncoding), and handles
concatenated bzip2 streams as bz2.decompress does. Add a truncated-block test.
Assisted-by: GitHub Copilot:claude-opus-4.8
* AVRO-4290: [python] Reject truncated deflate and short snappy blocks
Address review feedback:
- DeflateCodec: after flushing the decompressor, verify decompressor.eof so a
truncated/incomplete raw-deflate block is rejected with
InvalidAvroBinaryEncoding (zlib.decompress used to raise for this; the
decompressobj-based size cap otherwise silently accepted partial output).
- SnappyCodec: validate the block length is >= 4 before reading length - 4
bytes, raising a codec-specific InvalidAvroBinaryEncoding instead of falling
through to the generic decoder error.
Assisted-by: GitHub Copilot:claude-opus-4.8
* AVRO-4290: [python] Add a truncated-deflate-block rejection test
Cover the new DeflateCodec behavior (raising InvalidAvroBinaryEncoding when the
end-of-stream marker isn't reached) with a test that truncates a valid deflate
block and asserts decompress() rejects it, mirroring the bzip2 truncation test.
Assisted-by: GitHub Copilot:claude-opus-4.8
* AVRO-4290: [python] Bound the deflate flush() output too
The previous fix bounded decompress(data, limit+1) but then called
decompressor.flush() with no limit, so the residual output (from the
unconsumed input left by max_length) could still expand unbounded. Drain the
unconsumed_tail in a loop with a per-call max_length and pass a bounded length
to flush(), so the accumulated output can never exceed the limit by more than
one byte before being rejected.
Assisted-by: GitHub Copilot:claude-opus-4.8
* AVRO-4290: [python] Clamp AVRO_MAX_DECOMPRESS_LENGTH to sys.maxsize
_max_decompress_length() returned the raw parsed int. An absurdly large override
is passed as max_length to zlib/bz2 decompress(), which raise OverflowError when
it exceeds Py_ssize_t. Clamp to sys.maxsize so an oversized override is honored
as "effectively unbounded" instead of producing a confusing OverflowError.
Assisted-by: GitHub Copilot:claude-opus-4.8
* AVRO-4290: [python] Avoid limit+1 Py_ssize_t overflow at sys.maxsize
After clamping AVRO_MAX_DECOMPRESS_LENGTH to sys.maxsize, the deflate/bz2 paths
still computed `limit + 1` for the decompress() max_length, which overflows
Py_ssize_t (and raises OverflowError) when limit == sys.maxsize. Add
_decompress_read_ceiling(), which returns limit + 1 normally but sys.maxsize
when the limit is already sys.maxsize (no realistic block can exceed it), and
use it for the bounded read/flush in both paths.
Assisted-by: GitHub Copilot:claude-opus-4.8
> [python] Enforce a maximum decompressed block size
> --------------------------------------------------
>
> Key: AVRO-4290
> URL: https://issues.apache.org/jira/browse/AVRO-4290
> Project: Apache Avro
> Issue Type: Sub-task
> Components: python
> Affects Versions: 1.11.5, 1.12.1
> Reporter: Ismaël Mejía
> Assignee: Ismaël Mejía
> Priority: Major
> Labels: pull-request-available
> Fix For: 1.12.2
>
> Time Spent: 2h 40m
> Remaining Estimate: 0h
>
> The codecs in {{lang/py/avro/codecs.py}} decompress each block (deflate via
> {{zlib.decompress}} without a bufsize/limit, plus bzip2/snappy/zstandard)
> with no bound on the output size.
> Enforce a configurable maximum decompressed size and raise a clear error when
> a block would exceed it. Add a test with a high-ratio block.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)