*
* Jan Wieck
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.23 2006/10/05 23:33:33 tgl Exp $
+ * Copyright (c) 1999-2008, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.23.2.1 2008/05/28 21:58:08 tgl Exp $
* ----------
*/
#include "postgres.h"
* ----------
*/
static const PGLZ_Strategy strategy_default_data = {
- 256, /* Data chunks smaller 256 bytes are not
- * compressed */
- 6144, /* Data chunks greater equal 6K force
- * compression */
- /* except compressed result is greater uncompressed data */
- 20, /* Compression rates below 20% mean fallback
- * to uncompressed */
- /* storage except compression is forced by previous parameter */
+ 256, /* Data chunks less than 256 bytes are not
+ * compressed */
+ 6144, /* Data chunks >= 6K force compression, unless
+ * compressed output is larger than input */
+ 20, /* Below 6K, compression rates below 20% mean
+ * fallback to uncompressed */
128, /* Stop history lookup if a match of 128 bytes
- * is found */
+ * is found */
10 /* Lower good match size by 10% at every
- * lookup loop iteration. */
+ * lookup loop iteration */
};
-const PGLZ_Strategy * const PGLZ_strategy_default = &strategy_default_data;
+const PGLZ_Strategy *const PGLZ_strategy_default = &strategy_default_data;
static const PGLZ_Strategy strategy_always_data = {
- 0, /* Chunks of any size are compressed */
- 0, /* */
- 0, /* We want to save at least one single byte */
+ 0, /* Chunks of any size are compressed */
+ 0,
+ 0, /* It's enough to save one single byte */
128, /* Stop history lookup if a match of 128 bytes
- * is found */
- 6 /* Look harder for a good match. */
+ * is found */
+ 6 /* Look harder for a good match */
};
-const PGLZ_Strategy * const PGLZ_strategy_always = &strategy_always_data;
+const PGLZ_Strategy *const PGLZ_strategy_always = &strategy_always_data;
/* ----------
* If the strategy forbids compression (at all or if source chunk too
* small), fail.
*/
- if (strategy->match_size_good == 0 ||
+ if (strategy->match_size_good <= 0 ||
slen < strategy->min_input_size)
return false;
}
/*
- * Write out the last control byte and check that we haven't overrun
- * the output size allowed by the strategy.
+ * Write out the last control byte and check that we haven't overrun the
+ * output size allowed by the strategy.
*/
*ctrlp = ctrlb;
result_size = bp - bstart;
void
pglz_decompress(const PGLZ_Header *source, char *dest)
{
- const unsigned char *dp;
- const unsigned char *dend;
- unsigned char *bp;
- unsigned char ctrl;
- int32 ctrlc;
- int32 len;
- int32 off;
- int32 destsize;
-
- dp = ((const unsigned char *) source) + sizeof(PGLZ_Header);
- dend = ((const unsigned char *) source) + VARATT_SIZE(source);
- bp = (unsigned char *) dest;
+ const unsigned char *sp;
+ const unsigned char *srcend;
+ unsigned char *dp;
+ unsigned char *destend;
- while (dp < dend)
+ sp = ((const unsigned char *) source) + sizeof(PGLZ_Header);
+ srcend = ((const unsigned char *) source) + VARSIZE(source);
+ dp = (unsigned char *) dest;
+ destend = dp + source->rawsize;
+
+ while (sp < srcend && dp < destend)
{
/*
- * Read one control byte and process the next 8 items.
+ * Read one control byte and process the next 8 items (or as many
+ * as remain in the compressed input).
*/
- ctrl = *dp++;
- for (ctrlc = 0; ctrlc < 8 && dp < dend; ctrlc++)
+ unsigned char ctrl = *sp++;
+ int ctrlc;
+
+ for (ctrlc = 0; ctrlc < 8 && sp < srcend; ctrlc++)
{
if (ctrl & 1)
{
* coded as 18, another extension tag byte tells how much
* longer the match really was (0-255).
*/
- len = (dp[0] & 0x0f) + 3;
- off = ((dp[0] & 0xf0) << 4) | dp[1];
- dp += 2;
+ int32 len;
+ int32 off;
+
+ len = (sp[0] & 0x0f) + 3;
+ off = ((sp[0] & 0xf0) << 4) | sp[1];
+ sp += 2;
if (len == 18)
- len += *dp++;
+ len += *sp++;
+
+ /*
+ * Check for output buffer overrun, to ensure we don't
+ * clobber memory in case of corrupt input. Note: we must
+ * advance dp here to ensure the error is detected below
+ * the loop. We don't simply put the elog inside the loop
+ * since that will probably interfere with optimization.
+ */
+ if (dp + len > destend)
+ {
+ dp += len;
+ break;
+ }
/*
* Now we copy the bytes specified by the tag from OUTPUT to
*/
while (len--)
{
- *bp = bp[-off];
- bp++;
+ *dp = dp[-off];
+ dp++;
}
}
else
* An unset control bit means LITERAL BYTE. So we just copy
* one from INPUT to OUTPUT.
*/
- *bp++ = *dp++;
+ if (dp >= destend) /* check for buffer overrun */
+ break; /* do not clobber memory */
+
+ *dp++ = *sp++;
}
/*
}
/*
- * Check we decompressed the right amount, else die. This is a FATAL
- * condition if we tromped on more memory than expected (we assume we
- * have not tromped on shared memory, though, so need not PANIC).
+ * Check we decompressed the right amount.
*/
- destsize = (char *) bp - dest;
- if (destsize != source->rawsize)
- elog(destsize > source->rawsize ? FATAL : ERROR,
- "compressed data is corrupt");
+ if (dp != destend || sp != srcend)
+ elog(ERROR, "compressed data is corrupt");
/*
* That's it.