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


##########
lang/c++/impl/DataFile.cc:
##########
@@ -627,12 +679,39 @@ void DataFileReaderBase::readDataBlock() {
 
             const uint8_t *data;
             size_t len;
+            size_t maxLength = maxDecompressLength();
+            // zlib tracks output in a uLong (z_stream::total_out), which is 
only
+            // 32-bit on some platforms (e.g. Windows). Cap the working limit 
to
+            // uLong's range so the buffer-size arithmetic below (which uses
+            // total_out) cannot wrap when a larger AVRO_MAX_DECOMPRESS_LENGTH 
is
+            // configured.
+            const uLong zlibMax = std::numeric_limits<uLong>::max();
+            if (maxLength > zlibMax) {
+                maxLength = zlibMax;
+            }
             while (ret != Z_STREAM_END && st->next(&data, &len)) {
                 zs.avail_in = static_cast<uInt>(len);
                 zs.next_in = const_cast<Bytef *>(data);
                 do {
                     if (zs.total_out == uncompressed.size()) {
-                        uncompressed.resize(uncompressed.size() + 
zlibBufGrowSize);
+                        // Reject a block that would decompress to more than 
the
+                        // allowed maximum, before growing the buffer further.
+                        if (uncompressed.size() >= maxLength) {
+                            (void) inflateEnd(&zs);
+                            // At the trigger uncompressed.size() == maxLength 
and
+                            // inflate still has output, so the block is at 
least
+                            // maxLength + 1 bytes. Report that (like the 
snappy/zstd
+                            // errors) so the message is accurate and 
consistent.
+                            throw Exception(
+                                "Decompressed block size {} exceeds the 
maximum allowed of {} bytes",
+                                uncompressed.size() + 1, maxLength);

Review Comment:
   The over-limit deflate error reports `uncompressed.size() + 1`, which can 
wrap when `maxLength` is `SIZE_MAX` (or when `maxLength` is clamped to `uLong` 
max on 32-bit). That can yield a nonsensical size in the exception message 
(e.g., 0), undermining the intent of the limit diagnostics. Compute the 
would-be size with a saturating +1 to avoid overflow.



##########
lang/c++/impl/ZstdDecompressWrapper.cc:
##########
@@ -43,9 +43,21 @@ std::string ZstdDecompressWrapper::decompress(const 
std::vector<char> &compresse
             if (ZSTD_isError(ret)) {
                 throw Exception("ZSTD decompression error: {}", 
ZSTD_getErrorName(ret));
             }
+            // Reject before appending so the buffer never grows past the 
limit.
+            if (out.pos > maxLength - uncompressed.size()) {
+                throw Exception(
+                    "Decompressed block size {} exceeds the maximum allowed of 
{} bytes",
+                    uncompressed.size() + out.pos, maxLength);
+            }

Review Comment:
   In the Zstd streaming path, the exception formats `uncompressed.size() + 
out.pos`. If `maxLength` is configured near `SIZE_MAX`, that addition can 
overflow and produce an incorrect (wrapped) size in the error message. Use a 
saturating add when computing the reported size so the diagnostic remains 
accurate.



-- 
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