@@ -2789,21 +2789,44 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US
2789
2789
if (header->rhd_flags & rhd_incomplete)
2790
2790
{
2791
2791
p = fragment->rhdf_data ;
2792
- length -= offsetof (rhdf, rhdf_data[ 0 ]) ;
2792
+ length -= RHDF_SIZE ;
2793
2793
}
2794
2794
else if (header->rhd_flags & rhd_long_tranum)
2795
2795
{
2796
2796
p = ((rhde*) header)->rhde_data ;
2797
- length -= offsetof (rhde, rhde_data[ 0 ]) ;
2797
+ length -= RHDE_SIZE ;
2798
2798
}
2799
2799
else
2800
2800
{
2801
2801
p = header->rhd_data ;
2802
- length -= offsetof (rhd, rhd_data[ 0 ]) ;
2802
+ length -= RHD_SIZE ;
2803
2803
}
2804
2804
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);
2807
2830
2808
2831
// Next, chase down fragments, if any
2809
2832
@@ -2842,33 +2865,30 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US
2842
2865
if (fragment->rhdf_flags & rhd_incomplete)
2843
2866
{
2844
2867
p = fragment->rhdf_data ;
2845
- length -= offsetof (rhdf, rhdf_data[ 0 ]) ;
2868
+ length -= RHDF_SIZE ;
2846
2869
}
2847
2870
else if (fragment->rhdf_flags & rhd_long_tranum)
2848
2871
{
2849
2872
p = ((rhde*) fragment)->rhde_data ;
2850
- length -= offsetof (rhde, rhde_data[ 0 ]) ;
2873
+ length -= RHDE_SIZE ;
2851
2874
}
2852
2875
else
2853
2876
{
2854
2877
p = ((rhd*) fragment)->rhd_data ;
2855
- length -= offsetof (rhd, rhd_data[ 0 ]) ;
2878
+ length -= RHD_SIZE ;
2856
2879
}
2857
2880
2858
- record_length += (fragment->rhdf_flags & rhd_not_packed) ?
2859
- length : Compressor::getUnpackedLength (length, p);
2881
+ remainingLength -= calculateLength (length, p);
2860
2882
2861
2883
page_number = fragment->rhdf_f_page ;
2862
2884
line_number = fragment->rhdf_f_line ;
2863
2885
flags = fragment->rhdf_flags ;
2864
2886
release_page (&window);
2865
2887
}
2866
2888
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
2870
2890
2871
- if (!delta_flag && record_length != format-> fmt_length )
2891
+ if (!delta_flag && remainingLength != 0 )
2872
2892
return corrupt (VAL_REC_WRONG_LENGTH, relation, number.getValue ());
2873
2893
2874
2894
return rtn_ok;
0 commit comments