@@ -2789,21 +2789,44 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US
27892789 if (header->rhd_flags & rhd_incomplete)
27902790 {
27912791 p = fragment->rhdf_data ;
2792- length -= offsetof (rhdf, rhdf_data[ 0 ]) ;
2792+ length -= RHDF_SIZE ;
27932793 }
27942794 else if (header->rhd_flags & rhd_long_tranum)
27952795 {
27962796 p = ((rhde*) header)->rhde_data ;
2797- length -= offsetof (rhde, rhde_data[ 0 ]) ;
2797+ length -= RHDE_SIZE ;
27982798 }
27992799 else
28002800 {
28012801 p = header->rhd_data ;
2802- length -= offsetof (rhd, rhd_data[ 0 ]) ;
2802+ length -= RHD_SIZE ;
28032803 }
28042804
2805- ULONG record_length = (header->rhd_flags & rhd_not_packed) ?
2806- length : Compressor::getUnpackedLength (length, p);
2805+ const auto format = MET_format (vdr_tdbb, relation, header->rhd_format );
2806+ auto remainingLength = format->fmt_length ;
2807+
2808+ auto calculateLength = [fragment, remainingLength](ULONG length, const UCHAR* data)
2809+ {
2810+ if (fragment->rhdf_flags & rhd_not_packed)
2811+ {
2812+ if (length > remainingLength)
2813+ {
2814+ // Short records may be zero-padded up to the fragmented header size.
2815+ // Find out how many zero bytes present inside the tail and adjust
2816+ // the calculated record length accordingly.
2817+
2818+ auto tail = data + remainingLength;
2819+ for (const auto end = data + length; tail < end && !*tail; tail++)
2820+ length--;
2821+ }
2822+
2823+ return length;
2824+ }
2825+
2826+ return Compressor::getUnpackedLength (length, data);
2827+ };
2828+
2829+ remainingLength -= calculateLength (length, p);
28072830
28082831 // Next, chase down fragments, if any
28092832
@@ -2842,33 +2865,30 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US
28422865 if (fragment->rhdf_flags & rhd_incomplete)
28432866 {
28442867 p = fragment->rhdf_data ;
2845- length -= offsetof (rhdf, rhdf_data[ 0 ]) ;
2868+ length -= RHDF_SIZE ;
28462869 }
28472870 else if (fragment->rhdf_flags & rhd_long_tranum)
28482871 {
28492872 p = ((rhde*) fragment)->rhde_data ;
2850- length -= offsetof (rhde, rhde_data[ 0 ]) ;
2873+ length -= RHDE_SIZE ;
28512874 }
28522875 else
28532876 {
28542877 p = ((rhd*) fragment)->rhd_data ;
2855- length -= offsetof (rhd, rhd_data[ 0 ]) ;
2878+ length -= RHD_SIZE ;
28562879 }
28572880
2858- record_length += (fragment->rhdf_flags & rhd_not_packed) ?
2859- length : Compressor::getUnpackedLength (length, p);
2881+ remainingLength -= calculateLength (length, p);
28602882
28612883 page_number = fragment->rhdf_f_page ;
28622884 line_number = fragment->rhdf_f_line ;
28632885 flags = fragment->rhdf_flags ;
28642886 release_page (&window);
28652887 }
28662888
2867- // Check out record length and format
2868-
2869- const Format* format = MET_format (vdr_tdbb, relation, header->rhd_format );
2889+ // Validate unpacked record length
28702890
2871- if (!delta_flag && record_length != format-> fmt_length )
2891+ if (!delta_flag && remainingLength != 0 )
28722892 return corrupt (VAL_REC_WRONG_LENGTH, relation, number.getValue ());
28732893
28742894 return rtn_ok;
0 commit comments