Fix dead loop with kSkipAnyCorruptedRecords mode selected in some cases (#11955) (#11979)

Summary:
With fragmented record span across multiple blocks, if any following blocks corrupted with arbitary data, and intepreted log number less than the current log number, program will fall into infinite loop due to
not skipping buffer leading bytes

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11979

Test Plan: existing unit tests

Reviewed By: ajkr

Differential Revision: D50604408

Pulled By: jowlyzhang

fbshipit-source-id: e50a0c7e7c3d293fb9d5afec0a3eb4a1835b7a3b
This commit is contained in:
qiuchengxuan 2023-10-25 09:16:24 -07:00 committed by Facebook GitHub Bot
parent dc87847e65
commit f2c9075d16

View file

@ -469,12 +469,14 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result, size_t* drop_size,
const unsigned int type = header[6]; const unsigned int type = header[6];
const uint32_t length = a | (b << 8); const uint32_t length = a | (b << 8);
int header_size = kHeaderSize; int header_size = kHeaderSize;
if ((type >= kRecyclableFullType && type <= kRecyclableLastType) || const bool is_recyclable_type =
type == kRecyclableUserDefinedTimestampSizeType) { ((type >= kRecyclableFullType && type <= kRecyclableLastType) ||
type == kRecyclableUserDefinedTimestampSizeType);
if (is_recyclable_type) {
header_size = kRecyclableHeaderSize;
if (end_of_buffer_offset_ - buffer_.size() == 0) { if (end_of_buffer_offset_ - buffer_.size() == 0) {
recycled_ = true; recycled_ = true;
} }
header_size = kRecyclableHeaderSize;
// We need enough for the larger header // We need enough for the larger header
if (buffer_.size() < static_cast<size_t>(kRecyclableHeaderSize)) { if (buffer_.size() < static_cast<size_t>(kRecyclableHeaderSize)) {
int r = kEof; int r = kEof;
@ -483,11 +485,8 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result, size_t* drop_size,
} }
continue; continue;
} }
const uint32_t log_num = DecodeFixed32(header + 7);
if (log_num != log_number_) {
return kOldRecord;
}
} }
if (header_size + length > buffer_.size()) { if (header_size + length > buffer_.size()) {
assert(buffer_.size() >= static_cast<size_t>(header_size)); assert(buffer_.size() >= static_cast<size_t>(header_size));
*drop_size = buffer_.size(); *drop_size = buffer_.size();
@ -499,6 +498,14 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result, size_t* drop_size,
return kBadRecordLen; return kBadRecordLen;
} }
if (is_recyclable_type) {
const uint32_t log_num = DecodeFixed32(header + 7);
if (log_num != log_number_) {
buffer_.remove_prefix(header_size + length);
return kOldRecord;
}
}
if (type == kZeroType && length == 0) { if (type == kZeroType && length == 0) {
// Skip zero length record without reporting any drops since // Skip zero length record without reporting any drops since
// such records are produced by the mmap based writing code in // such records are produced by the mmap based writing code in