@@ -519,6 +519,44 @@ gorilla_compressor_finish(GorillaCompressor *compressor)
519519 *** DecompressionIterator ***
520520 *******************************/
521521
522+ static inline uint32
523+ decompression_iterator_items_seen (const GorillaDecompressionIterator * iter )
524+ {
525+ if (iter -> has_nulls )
526+ {
527+ return iter -> nulls .num_elements_returned ;
528+ }
529+ else
530+ {
531+ return iter -> tag0s .num_elements_returned ;
532+ }
533+ }
534+
535+ static inline uint32
536+ decompression_iterator_item_count (const GorillaDecompressionIterator * iter )
537+ {
538+ if (iter -> has_nulls )
539+ {
540+ return iter -> nulls .num_elements ;
541+ }
542+ else
543+ {
544+ return iter -> tag0s .num_elements ;
545+ }
546+ }
547+
548+ static inline uint32
549+ decompression_iterator_values_seen (const GorillaDecompressionIterator * iter )
550+ {
551+ return iter -> tag0s .num_elements_returned ;
552+ }
553+
554+ static inline uint32
555+ decompression_iterator_value_count (const GorillaDecompressionIterator * iter )
556+ {
557+ return iter -> tag0s .num_elements ;
558+ }
559+
522560inline static void
523561bytes_attach_bit_array_and_advance (BitArray * dst , StringInfo si , uint32 num_buckets ,
524562 uint8 bits_in_last_bucket )
@@ -560,11 +598,29 @@ compressed_gorilla_data_init_from_stringinfo(CompressedGorillaData *expanded, St
560598 if (has_nulls )
561599 {
562600 expanded -> nulls = bytes_deserialize_simple8b_and_advance (si );
601+ CheckCompressedData (expanded -> nulls -> num_elements >=
602+ expanded -> num_bits_used_per_xor -> num_elements );
603+ CheckCompressedData (expanded -> nulls -> num_elements >= expanded -> tag0s -> num_elements );
604+ CheckCompressedData (expanded -> nulls -> num_elements >= expanded -> tag1s -> num_elements );
563605 }
564606 else
565607 {
566608 expanded -> nulls = NULL ;
567609 }
610+
611+ /* XOR bit count must be reasonable */
612+ uint64 xor_bit_count = bit_array_num_bits (& expanded -> xors );
613+ CheckCompressedData (xor_bit_count <= expanded -> tag0s -> num_elements * 64 );
614+
615+ /* leading zeros have a fixed size and we need at least one item */
616+ uint64 num_leading_zeros_bits = bit_array_num_bits (& expanded -> leading_zeros );
617+ CheckCompressedData (num_leading_zeros_bits >= BITS_PER_LEADING_ZEROS &&
618+ num_leading_zeros_bits % BITS_PER_LEADING_ZEROS == 0 &&
619+ num_leading_zeros_bits <=
620+ expanded -> tag0s -> num_elements * BITS_PER_LEADING_ZEROS );
621+
622+ /* tag bits must be reasonable too */
623+ CheckCompressedData (expanded -> tag0s -> num_elements >= expanded -> tag1s -> num_elements );
568624}
569625
570626static void
@@ -672,6 +728,12 @@ gorilla_decompression_iterator_try_next_forward_internal(GorillaDecompressionIte
672728 /* Could slightly improve performance here by not returning a tail of non-null bits */
673729 if (null .is_done )
674730 {
731+ /* make sure we exhausted all items before */
732+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
733+ decompression_iterator_item_count (iter ));
734+ /* and also that we returned all values */
735+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
736+ decompression_iterator_value_count (iter ));
675737 return (DecompressResultInternal ){
676738 .is_done = true,
677739 };
@@ -689,6 +751,10 @@ gorilla_decompression_iterator_try_next_forward_internal(GorillaDecompressionIte
689751 /* if we don't have a null bitset, this will determine when we're done */
690752 if (tag0 .is_done )
691753 {
754+ /* make sure we exhausted all items before */
755+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
756+ decompression_iterator_item_count (iter ));
757+
692758 CheckCompressedData (!iter -> has_nulls );
693759 return (DecompressResultInternal ){
694760 .is_done = true,
@@ -799,7 +865,7 @@ gorilla_decompression_iterator_from_datum_reverse(Datum gorilla_compressed, Oid
799865 iter -> prev_leading_zeroes =
800866 bit_array_iter_next_rev (& iter -> leading_zeros , BITS_PER_LEADING_ZEROS );
801867 num_xor_bits = simple8brle_decompression_iterator_try_next_reverse (& iter -> num_bits_used );
802- Assert (!num_xor_bits .is_done );
868+ CheckCompressedData (!num_xor_bits .is_done );
803869 iter -> prev_xor_bits_used = num_xor_bits .val ;
804870 iter -> prev_val = iter -> gorilla_data .header -> last_value ;
805871 return & iter -> base ;
@@ -820,6 +886,12 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
820886
821887 if (null .is_done )
822888 {
889+ /* make sure we exhausted all items before */
890+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
891+ decompression_iterator_item_count (iter ));
892+ /* and also that we returned all values */
893+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
894+ decompression_iterator_value_count (iter ));
823895 return (DecompressResultInternal ){
824896 .is_done = true,
825897 };
@@ -839,6 +911,9 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
839911 /* if we don't have a null bitset, this will determine when we're done */
840912 if (tag0 .is_done )
841913 {
914+ /* make sure we exhausted all items before */
915+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
916+ decompression_iterator_item_count (iter ));
842917 return (DecompressResultInternal ){
843918 .is_done = true,
844919 };
@@ -851,6 +926,12 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
851926 };
852927 }
853928
929+ /* make sure we are in a valid state */
930+ tag1 = simple8brle_decompression_iterator_try_next_reverse (& iter -> tag1s );
931+ CheckCompressedData (!tag1 .is_done );
932+
933+ /* check that we have this much to read */
934+ CheckCompressedData (bit_array_iter_position (& iter -> xors ) >= iter -> prev_xor_bits_used );
854935 xor = bit_array_iter_next_rev (& iter -> xors , iter -> prev_xor_bits_used );
855936
856937 if (iter -> prev_leading_zeroes + iter -> prev_xor_bits_used < 64 )
@@ -859,8 +940,6 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
859940 }
860941 iter -> prev_val ^= xor ;
861942
862- tag1 = simple8brle_decompression_iterator_try_next_reverse (& iter -> tag1s );
863-
864943 if (tag1 .val != 0 )
865944 {
866945 /* get new xor sizes */
@@ -875,9 +954,15 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
875954 }
876955 else
877956 {
957+ /* make sure we have enough bits to read for the leading zeros */
958+ CheckCompressedData (bit_array_iter_position (& iter -> leading_zeros ) >=
959+ BITS_PER_LEADING_ZEROS );
878960 iter -> prev_xor_bits_used = num_xor_bits .val ;
879961 iter -> prev_leading_zeroes =
880962 bit_array_iter_next_rev (& iter -> leading_zeros , BITS_PER_LEADING_ZEROS );
963+
964+ /* more than 64 bits of data doesn't make sense */
965+ CheckCompressedData (iter -> prev_leading_zeroes + iter -> prev_xor_bits_used <= 64 );
881966 }
882967 }
883968
0 commit comments