Second thoughts on TOAST decompression.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Nov 2020 16:25:18 +0000 (11:25 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Nov 2020 16:25:18 +0000 (11:25 -0500)
On detecting a corrupted match tag, pglz_decompress() should just
summarily return -1.  Breaking out of the loop, as I did in dfc797730,
doesn't quite guarantee that will happen.  Also, we can use
unlikely() on that check, just in case it helps.

Backpatch to v13, like the previous patch.

src/common/pg_lzcompress.c

index 79747767ce08a0144b85d3496d8def6b74071825..f9c29820e30bd584d7ec4636a6043b0864a30318 100644 (file)
@@ -680,9 +680,12 @@ pglz_compress(const char *source, int32 slen, char *dest,
  * pglz_decompress -
  *
  *     Decompresses source into dest. Returns the number of bytes
- *     decompressed in the destination buffer, and *optionally*
- *     checks that both the source and dest buffers have been
- *     fully read and written to, respectively.
+ *     decompressed into the destination buffer, or -1 if the
+ *     compressed data is corrupted.
+ *
+ *     If check_complete is true, the data is considered corrupted
+ *     if we don't exactly fill the destination buffer.  Callers that
+ *     are extracting a slice typically can't apply this check.
  * ----------
  */
 int32
@@ -736,8 +739,8 @@ pglz_decompress(const char *source, int32 slen, char *dest,
                 * must check this, else we risk an infinite loop below in the
                 * face of corrupt data.)
                 */
-               if (sp > srcend || off == 0)
-                   break;
+               if (unlikely(sp > srcend || off == 0))
+                   return -1;
 
                /*
                 * Don't emit more data than requested.
@@ -809,9 +812,7 @@ pglz_decompress(const char *source, int32 slen, char *dest,
    }
 
    /*
-    * Check we decompressed the right amount. If we are slicing, then we
-    * won't necessarily be at the end of the source or dest buffers when we
-    * hit a stop, so we don't test them.
+    * If requested, check we decompressed the right amount.
     */
    if (check_complete && (dp != destend || sp != srcend))
        return -1;