summaryrefslogtreecommitdiff
path: root/file/file_prefetch_buffer.cc
diff options
context:
space:
mode:
authoranand76 <anand76@devvm4702.ftw0.facebook.com>2022-12-21 09:15:53 -0800
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>2022-12-21 09:15:53 -0800
commitdbf37c290ae0cbf1532f706942c098380cb9c53a (patch)
tree0e3d48146055eef48a24877331524188ca6778ab /file/file_prefetch_buffer.cc
parent53b703eafef16c20bad64171f1dcca8cc98eefa0 (diff)
Fix async prefetch heap use after free (#11049)
Summary: This PR fixes a heap use after free bug in the async prefetch code that happens in the following scenario - 1. Scan thread starts 2 async reads for Seek, one for the seek block and one for prefetching 2. Before the first read in https://github.com/facebook/rocksdb/issues/1 completes, another thread reads and loads the block in cache 3. The first scan thread finds the block in cache, continues and the next block cache miss is for a block that spans the boundary of the 2 prefetch buffers, and the 1st read is complete but the 2nd one is not complete yet 4. The scan thread will reallocate (i.e free the old buffer and allocate a new one) the 2nd prefetch buffer, and the in-progress prefetch is orphaned 5. The orphaned prefetch finally completes, resulting in a use after free Also add a few asserts to surface bugs earlier in the crash tests. Pull Request resolved: https://github.com/facebook/rocksdb/pull/11049 Test Plan: Repro with db_stress and verify the fix Reviewed By: akankshamahajan15 Differential Revision: D42181118 Pulled By: anand1976 fbshipit-source-id: 1ac55d2f64a89ce128c1c574262b8aa7d82eb8cc
Diffstat (limited to 'file/file_prefetch_buffer.cc')
-rw-r--r--file/file_prefetch_buffer.cc15
1 files changed, 14 insertions, 1 deletions
diff --git a/file/file_prefetch_buffer.cc b/file/file_prefetch_buffer.cc
index 9ea9129e2..4ac0d0504 100644
--- a/file/file_prefetch_buffer.cc
+++ b/file/file_prefetch_buffer.cc
@@ -247,10 +247,14 @@ void FilePrefetchBuffer::AbortAllIOs() {
// Release io_handles.
if (bufs_[curr_].io_handle_ != nullptr && bufs_[curr_].del_fn_ != nullptr) {
DestroyAndClearIOHandle(curr_);
+ } else {
+ bufs_[curr_].async_read_in_progress_ = false;
}
if (bufs_[second].io_handle_ != nullptr && bufs_[second].del_fn_ != nullptr) {
DestroyAndClearIOHandle(second);
+ } else {
+ bufs_[second].async_read_in_progress_ = false;
}
}
@@ -325,7 +329,16 @@ Status FilePrefetchBuffer::HandleOverlappingData(
uint64_t& tmp_offset, size_t& tmp_length) {
Status s;
size_t alignment = reader->file()->GetRequiredBufferAlignment();
- uint32_t second = curr_ ^ 1;
+ uint32_t second;
+
+ // Check if the first buffer has the required offset and the async read is
+ // still in progress. This should only happen if a prefetch was initiated
+ // by Seek, but the next access is at another offset.
+ if (bufs_[curr_].async_read_in_progress_ &&
+ IsOffsetInBufferWithAsyncProgress(offset, curr_)) {
+ PollAndUpdateBuffersIfNeeded(offset);
+ }
+ second = curr_ ^ 1;
// If data is overlapping over two buffers, copy the data from curr_ and
// call ReadAsync on curr_.