@@ -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,12 @@ 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+ /* and also that we returned all values */
758+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
759+ decompression_iterator_value_count (iter ));
692760 CheckCompressedData (!iter -> has_nulls );
693761 return (DecompressResultInternal ){
694762 .is_done = true,
@@ -799,7 +867,7 @@ gorilla_decompression_iterator_from_datum_reverse(Datum gorilla_compressed, Oid
799867 iter -> prev_leading_zeroes =
800868 bit_array_iter_next_rev (& iter -> leading_zeros , BITS_PER_LEADING_ZEROS );
801869 num_xor_bits = simple8brle_decompression_iterator_try_next_reverse (& iter -> num_bits_used );
802- Assert (!num_xor_bits .is_done );
870+ CheckCompressedData (!num_xor_bits .is_done );
803871 iter -> prev_xor_bits_used = num_xor_bits .val ;
804872 iter -> prev_val = iter -> gorilla_data .header -> last_value ;
805873 return & iter -> base ;
@@ -820,6 +888,12 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
820888
821889 if (null .is_done )
822890 {
891+ /* make sure we exhausted all items before */
892+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
893+ decompression_iterator_item_count (iter ));
894+ /* and also that we returned all values */
895+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
896+ decompression_iterator_value_count (iter ));
823897 return (DecompressResultInternal ){
824898 .is_done = true,
825899 };
@@ -839,6 +913,12 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
839913 /* if we don't have a null bitset, this will determine when we're done */
840914 if (tag0 .is_done )
841915 {
916+ /* make sure we exhausted all items before */
917+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
918+ decompression_iterator_item_count (iter ));
919+ /* and also that we returned all values */
920+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
921+ decompression_iterator_value_count (iter ));
842922 return (DecompressResultInternal ){
843923 .is_done = true,
844924 };
@@ -851,6 +931,13 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
851931 };
852932 }
853933
934+ /* make sure we are in a valid state */
935+ tag1 = simple8brle_decompression_iterator_try_next_reverse (& iter -> tag1s );
936+ CheckCompressedData (!tag1 .is_done );
937+
938+ /* check that we have this much to read */
939+ CheckCompressedData (iter -> prev_leading_zeroes + iter -> prev_xor_bits_used > 0 );
940+ CheckCompressedData (bit_array_iter_position (& iter -> xors ) >= iter -> prev_xor_bits_used );
854941 xor = bit_array_iter_next_rev (& iter -> xors , iter -> prev_xor_bits_used );
855942
856943 if (iter -> prev_leading_zeroes + iter -> prev_xor_bits_used < 64 )
@@ -859,8 +946,6 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
859946 }
860947 iter -> prev_val ^= xor ;
861948
862- tag1 = simple8brle_decompression_iterator_try_next_reverse (& iter -> tag1s );
863-
864949 if (tag1 .val != 0 )
865950 {
866951 /* get new xor sizes */
@@ -875,9 +960,15 @@ gorilla_decompression_iterator_try_next_reverse_internal(GorillaDecompressionIte
875960 }
876961 else
877962 {
963+ /* make sure we have enough bits to read for the leading zeros */
964+ CheckCompressedData (bit_array_iter_position (& iter -> leading_zeros ) >=
965+ BITS_PER_LEADING_ZEROS );
878966 iter -> prev_xor_bits_used = num_xor_bits .val ;
879967 iter -> prev_leading_zeroes =
880968 bit_array_iter_next_rev (& iter -> leading_zeros , BITS_PER_LEADING_ZEROS );
969+
970+ /* more than 64 bits of data doesn't make sense */
971+ CheckCompressedData (iter -> prev_leading_zeroes + iter -> prev_xor_bits_used <= 64 );
881972 }
882973 }
883974
0 commit comments