166166 *
167167 * Copyright (c) 1999-2008, PostgreSQL Global Development Group
168168 *
169- * $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.30 2008/03/07 23:20:21 tgl Exp $
169+ * $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.31 2008/03/08 01:09:36 tgl Exp $
170170 * ----------
171171 */
172172#include "postgres.h"
@@ -641,26 +641,26 @@ pglz_compress(const char *source, int32 slen, PGLZ_Header *dest,
641641void
642642pglz_decompress (const PGLZ_Header * source ,char * dest )
643643{
644- const unsignedchar * dp ;
645- const unsignedchar * dend ;
646- unsignedchar * bp ;
647- unsignedchar ctrl ;
648- int32 ctrlc ;
649- int32 len ;
650- int32 off ;
651- int32 destsize ;
652-
653- dp = ((const unsignedchar * )source )+ sizeof (PGLZ_Header );
654- dend = ((const unsignedchar * )source )+ VARSIZE (source );
655- bp = (unsignedchar * )dest ;
644+ const unsignedchar * sp ;
645+ const unsignedchar * srcend ;
646+ unsignedchar * dp ;
647+ unsignedchar * destend ;
656648
657- while (dp < dend )
649+ sp = ((const unsignedchar * )source )+ sizeof (PGLZ_Header );
650+ srcend = ((const unsignedchar * )source )+ VARSIZE (source );
651+ dp = (unsignedchar * )dest ;
652+ destend = dp + source -> rawsize ;
653+
654+ while (sp < srcend && dp < destend )
658655{
659656/*
660- * Read one control byte and process the next 8 items.
657+ * Read one control byte and process the next 8 items (or as many
658+ * as remain in the compressed input).
661659 */
662- ctrl = * dp ++ ;
663- for (ctrlc = 0 ;ctrlc < 8 && dp < dend ;ctrlc ++ )
660+ unsignedchar ctrl = * sp ++ ;
661+ int ctrlc ;
662+
663+ for (ctrlc = 0 ;ctrlc < 8 && sp < srcend ;ctrlc ++ )
664664{
665665if (ctrl & 1 )
666666{
@@ -671,11 +671,27 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
671671 * coded as 18, another extension tag byte tells how much
672672 * longer the match really was (0-255).
673673 */
674- len = (dp [0 ]& 0x0f )+ 3 ;
675- off = ((dp [0 ]& 0xf0 ) <<4 ) |dp [1 ];
676- dp += 2 ;
674+ int32 len ;
675+ int32 off ;
676+
677+ len = (sp [0 ]& 0x0f )+ 3 ;
678+ off = ((sp [0 ]& 0xf0 ) <<4 ) |sp [1 ];
679+ sp += 2 ;
677680if (len == 18 )
678- len += * dp ++ ;
681+ len += * sp ++ ;
682+
683+ /*
684+ * Check for output buffer overrun, to ensure we don't
685+ * clobber memory in case of corrupt input. Note: we must
686+ * advance dp here to ensure the error is detected below
687+ * the loop. We don't simply put the elog inside the loop
688+ * since that will probably interfere with optimization.
689+ */
690+ if (dp + len > destend )
691+ {
692+ dp += len ;
693+ break ;
694+ }
679695
680696/*
681697 * Now we copy the bytes specified by the tag from OUTPUT to
@@ -685,8 +701,8 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
685701 */
686702while (len -- )
687703{
688- * bp = bp [- off ];
689- bp ++ ;
704+ * dp = dp [- off ];
705+ dp ++ ;
690706}
691707}
692708else
@@ -695,7 +711,10 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
695711 * An unset control bit means LITERAL BYTE. So we just copy
696712 * one from INPUT to OUTPUT.
697713 */
698- * bp ++ = * dp ++ ;
714+ if (dp >=destend )/* check for buffer overrun */
715+ break ;/* do not clobber memory */
716+
717+ * dp ++ = * sp ++ ;
699718}
700719
701720/*
@@ -706,14 +725,10 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
706725}
707726
708727/*
709- * Check we decompressed the right amount, else die. This is a FATAL
710- * condition if we tromped on more memory than expected (we assume we have
711- * not tromped on shared memory, though, so need not PANIC).
728+ * Check we decompressed the right amount.
712729 */
713- destsize = (char * )bp - dest ;
714- if (destsize != source -> rawsize )
715- elog (destsize > source -> rawsize ?FATAL :ERROR ,
716- "compressed data is corrupt" );
730+ if (dp != destend || sp != srcend )
731+ elog (ERROR ,"compressed data is corrupt" );
717732
718733/*
719734 * That's it.