Copilot commented on code in PR #3850:
URL: https://github.com/apache/avro/pull/3850#discussion_r3568128140


##########
lang/py/avro/codecs.py:
##########
@@ -123,7 +180,31 @@ def decompress(readers_decoder: avro.io.BinaryDecoder) -> 
avro.io.BinaryDecoder:
         data = readers_decoder.read_bytes()
         # -15 is the log of the window size; negative indicates
         # "raw" (no zlib headers) decompression.  See zlib.h.
-        uncompressed = zlib.decompress(data, -15)
+        limit = _max_decompress_length()
+        decompressor = zlib.decompressobj(-15)
+        # Decompress in bounded steps: request at most (limit + 1 - produced)
+        # bytes each call so the accumulated output can never exceed the limit 
by
+        # more than one byte before being rejected. decompress()'s max_length
+        # leaves unconsumed input in unconsumed_tail, and flush() would 
otherwise
+        # emit the remainder unbounded, so drain the tail in a loop and bound 
the
+        # final flush too.
+        uncompressed = bytearray()
+        pending = data
+        while True:
+            want = limit + 1 - len(uncompressed)
+            uncompressed += decompressor.decompress(pending, want)
+            if len(uncompressed) > limit:
+                _raise_decompression_too_large(limit)
+            pending = decompressor.unconsumed_tail
+            if not pending:
+                break
+        uncompressed += decompressor.flush(limit + 1 - len(uncompressed))

Review Comment:
   When AVRO_MAX_DECOMPRESS_LENGTH is set to a very large value, 
`_max_decompress_length()` clamps it to `sys.maxsize`, but the deflate path 
still computes `limit + 1` for the `max_length` argument. If `limit == 
sys.maxsize`, `limit + 1` overflows `Py_ssize_t` and `zlib` can raise 
`OverflowError`, defeating the intent of the clamping. Compute a capped `cap` 
(no `+ 1` when `limit == sys.maxsize`) and ensure `want` stays >= 1 for 
progress.



##########
lang/py/avro/codecs.py:
##########
@@ -139,7 +220,30 @@ def compress(data: bytes) -> Tuple[bytes, int]:
         def decompress(readers_decoder: avro.io.BinaryDecoder) -> 
avro.io.BinaryDecoder:
             length = readers_decoder.read_long()
             data = readers_decoder.read(length)
-            uncompressed = bz2.decompress(data)
+            limit = _max_decompress_length()
+            uncompressed = bytearray()
+            decompressor = bz2.BZ2Decompressor()
+            input_data = data
+            while True:
+                # Request enough to detect exceeding the limit without 
allocating
+                # the full (potentially huge) output.
+                want = limit + 1 - len(uncompressed)
+                if want <= 0:
+                    want = 1
+                uncompressed += decompressor.decompress(input_data, want)

Review Comment:
   Same `limit + 1` overflow risk as the deflate path: if the env override is 
clamped to `sys.maxsize`, `want = limit + 1 - len(uncompressed)` can become 
`sys.maxsize + 1` and `bz2.BZ2Decompressor.decompress(..., max_length=want)` 
may raise `OverflowError`. Use a `cap` that avoids `+ 1` at `sys.maxsize`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to