@@ -798,8 +798,9 @@ impl<B: Blob> Append<B> {
798798 ///
799799 /// Since larger valid lengths are authoritative, a shorter CRC cannot simply be written next to
800800 /// the old CRC. We first stage the shorter slot with length 0, then make its length durable,
801- /// then invalidate the old longer slot. A crash during any phase recovers either the old longer
802- /// page or the new shorter page, but never loses the whole page or fabricates a larger length.
801+ /// then clear the old slot's CRC bytes before clearing its length bytes. A crash during any
802+ /// phase recovers either the old longer page or the new shorter page, but never loses the whole
803+ /// page or fabricates a larger length.
803804 async fn sync_partial_page_shrink (
804805 blob : & B ,
805806 page : u64 ,
@@ -821,36 +822,40 @@ impl<B: Blob> Append<B> {
821822 } else {
822823 0
823824 } ;
825+ let new_slot_offset = crc_start
826+ . checked_add ( new_slot_start as u64 )
827+ . ok_or ( Error :: OffsetOverflow ) ?;
824828 let staged_slot = Self :: checksum_slot_bytes ( 0 , new_crc) ;
825- blob. write_at ( crc_start + new_slot_start as u64 , staged_slot. to_vec ( ) )
829+ blob. write_at ( new_slot_offset , staged_slot. to_vec ( ) )
826830 . await ?;
827831 blob. sync ( ) . await ?;
828832
829- blob. write_at (
830- crc_start + new_slot_start as u64 ,
831- new_len. to_be_bytes ( ) . to_vec ( ) ,
832- )
833- . await ?;
833+ blob. write_at ( new_slot_offset, new_len. to_be_bytes ( ) . to_vec ( ) )
834+ . await ?;
834835 blob. sync ( ) . await ?;
835836
836837 let old_slot_start = if new_slot_start == 0 {
837838 CHECKSUM_SLOT_SIZE
838839 } else {
839840 0
840841 } ;
842+ let old_slot_offset = crc_start
843+ . checked_add ( old_slot_start as u64 )
844+ . ok_or ( Error :: OffsetOverflow ) ?;
841845 let len_size = std:: mem:: size_of :: < u16 > ( ) ;
842846 let crc_size = CHECKSUM_SLOT_SIZE - len_size;
843- blob. write_at (
844- crc_start + old_slot_start as u64 + len_size as u64 ,
845- vec ! [ 0u8 ; crc_size] ,
846- )
847- . await ?;
848- blob. sync ( ) . await ?;
847+ let old_crc_offset = old_slot_offset
848+ . checked_add ( len_size as u64 )
849+ . ok_or ( Error :: OffsetOverflow ) ?;
849850
850- blob. write_at ( crc_start + old_slot_start as u64 , vec ! [ 0u8 ; len_size] )
851+ // Clear CRC bytes before length bytes so torn invalidation cannot create a new valid slot.
852+ blob. write_at ( old_crc_offset, vec ! [ 0u8 ; crc_size] )
851853 . await ?;
852854 blob. sync ( ) . await ?;
853855
856+ blob. write_at ( old_slot_offset, vec ! [ 0u8 ; len_size] ) . await ?;
857+ blob. sync ( ) . await ?;
858+
854859 let final_record = if new_slot_start == 0 {
855860 Checksum {
856861 len1 : new_len,
0 commit comments