fix use after free in flush_range and flush_iovec
Calling blocks_flushed can cause the piece entry to be freed so its callers need to be aware of that and avoid dereferencing the pointer if the entry is freed.
This commit is contained in:
parent
366b7983d1
commit
f5e33932d2
|
@ -440,7 +440,8 @@ namespace libtorrent
|
|||
// used to convert dirty blocks into non-dirty ones
|
||||
// i.e. from being part of the write cache to being part
|
||||
// of the read cache. it's used when flushing blocks to disk
|
||||
void blocks_flushed(cached_piece_entry* pe, int const* flushed, int num_flushed);
|
||||
// returns true if the piece entry was freed
|
||||
bool blocks_flushed(cached_piece_entry* pe, int const* flushed, int num_flushed);
|
||||
|
||||
// adds a block to the cache, marks it as dirty and
|
||||
// associates the job with it. When the block is
|
||||
|
|
|
@ -477,7 +477,8 @@ namespace libtorrent
|
|||
, file::iovec_t* iov, int* flushing, int block_base_index = 0);
|
||||
void flush_iovec(cached_piece_entry* pe, file::iovec_t const* iov, int const* flushing
|
||||
, int num_blocks, storage_error& error);
|
||||
void iovec_flushed(cached_piece_entry* pe
|
||||
// returns true if the piece entry was freed
|
||||
bool iovec_flushed(cached_piece_entry* pe
|
||||
, int* flushing, int num_blocks, int block_offset
|
||||
, storage_error const& error
|
||||
, jobqueue_t& completed_jobs);
|
||||
|
|
|
@ -793,7 +793,7 @@ cached_piece_entry* block_cache::add_dirty_block(disk_io_job* j)
|
|||
// (since these blocks now are part of the read cache) the refcounts of the
|
||||
// blocks are also decremented by this function. They are expected to have been
|
||||
// incremented by the caller.
|
||||
void block_cache::blocks_flushed(cached_piece_entry* pe, int const* flushed, int num_flushed)
|
||||
bool block_cache::blocks_flushed(cached_piece_entry* pe, int const* flushed, int num_flushed)
|
||||
{
|
||||
TORRENT_PIECE_ASSERT(pe->in_use, pe);
|
||||
|
||||
|
@ -817,7 +817,7 @@ void block_cache::blocks_flushed(cached_piece_entry* pe, int const* flushed, int
|
|||
pe->num_dirty -= num_flushed;
|
||||
|
||||
update_cache_state(pe);
|
||||
maybe_free_piece(pe);
|
||||
return maybe_free_piece(pe);
|
||||
}
|
||||
|
||||
std::pair<block_cache::iterator, block_cache::iterator> block_cache::all_pieces() const
|
||||
|
|
|
@ -676,7 +676,7 @@ namespace libtorrent
|
|||
// It is necessary to call this function with the blocks produced by
|
||||
// build_iovec, to reset their state to not being flushed anymore
|
||||
// the cache needs to be locked when calling this function
|
||||
void disk_io_thread::iovec_flushed(cached_piece_entry* pe
|
||||
bool disk_io_thread::iovec_flushed(cached_piece_entry* pe
|
||||
, int* flushing, int num_blocks, int block_offset
|
||||
, storage_error const& error
|
||||
, jobqueue_t& completed_jobs)
|
||||
|
@ -691,7 +691,8 @@ namespace libtorrent
|
|||
DLOG("%d ", flushing[i]);
|
||||
DLOG("]\n");
|
||||
#endif
|
||||
m_disk_cache.blocks_flushed(pe, flushing, num_blocks);
|
||||
if (m_disk_cache.blocks_flushed(pe, flushing, num_blocks))
|
||||
return true;
|
||||
|
||||
int block_size = m_disk_cache.block_size();
|
||||
|
||||
|
@ -721,6 +722,8 @@ namespace libtorrent
|
|||
j = next;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// issues write operations for blocks in the given
|
||||
|
@ -756,8 +759,7 @@ namespace libtorrent
|
|||
|
||||
TORRENT_PIECE_ASSERT(pe->piece_refcount > 0, pe);
|
||||
--pe->piece_refcount;
|
||||
iovec_flushed(pe, flushing, iov_len, 0, error, completed_jobs);
|
||||
|
||||
if (!iovec_flushed(pe, flushing, iov_len, 0, error, completed_jobs))
|
||||
m_disk_cache.maybe_free_piece(pe);
|
||||
|
||||
// if the cache is under high pressure, we need to evict
|
||||
|
|
Loading…
Reference in New Issue