make disk_buffer_holder know the size of the bufer it holds, to fix buffer overrun in chained_buffer
fix
This commit is contained in:
parent
58a76e26a8
commit
8adcfdbf41
|
@ -112,10 +112,10 @@ namespace libtorrent {
|
||||||
#if TORRENT_CPP98_DEQUE
|
#if TORRENT_CPP98_DEQUE
|
||||||
move_construct_holder_fun move_holder;
|
move_construct_holder_fun move_holder;
|
||||||
#endif
|
#endif
|
||||||
aux::aligned_storage<24>::type holder;
|
aux::aligned_storage<32>::type holder;
|
||||||
char* buf; // the first byte of the buffer
|
char* buf = nullptr; // the first byte of the buffer
|
||||||
int size; // the total size of the buffer
|
int size = 0; // the total size of the buffer
|
||||||
int used_size; // this is the number of bytes to send/receive
|
int used_size = 0; // this is the number of bytes to send/receive
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -63,7 +63,8 @@ namespace libtorrent {
|
||||||
struct TORRENT_EXTRA_EXPORT disk_buffer_holder
|
struct TORRENT_EXTRA_EXPORT disk_buffer_holder
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
disk_buffer_holder(buffer_allocator_interface& alloc, char* buf) noexcept;
|
disk_buffer_holder(buffer_allocator_interface& alloc
|
||||||
|
, char* buf, std::size_t sz) noexcept;
|
||||||
|
|
||||||
disk_buffer_holder& operator=(disk_buffer_holder&&) noexcept;
|
disk_buffer_holder& operator=(disk_buffer_holder&&) noexcept;
|
||||||
disk_buffer_holder(disk_buffer_holder&&) noexcept;
|
disk_buffer_holder(disk_buffer_holder&&) noexcept;
|
||||||
|
@ -75,7 +76,9 @@ namespace libtorrent {
|
||||||
// using a disk buffer pool directly (there's only one
|
// using a disk buffer pool directly (there's only one
|
||||||
// disk_buffer_pool per session)
|
// disk_buffer_pool per session)
|
||||||
disk_buffer_holder(buffer_allocator_interface& alloc
|
disk_buffer_holder(buffer_allocator_interface& alloc
|
||||||
, aux::block_cache_reference const& ref, char* buf) noexcept;
|
, aux::block_cache_reference const& ref
|
||||||
|
, char* buf
|
||||||
|
, std::size_t sz) noexcept;
|
||||||
|
|
||||||
// frees any unreleased disk buffer held by this object
|
// frees any unreleased disk buffer held by this object
|
||||||
~disk_buffer_holder();
|
~disk_buffer_holder();
|
||||||
|
@ -92,14 +95,15 @@ namespace libtorrent {
|
||||||
// set the holder object to hold the specified buffer
|
// set the holder object to hold the specified buffer
|
||||||
// (or nullptr by default). If it's already holding a
|
// (or nullptr by default). If it's already holding a
|
||||||
// disk buffer, it will first be freed.
|
// disk buffer, it will first be freed.
|
||||||
void reset(char* buf = nullptr);
|
void reset(char* buf = nullptr, std::size_t sz = 0);
|
||||||
void reset(aux::block_cache_reference const& ref, char* buf);
|
void reset(aux::block_cache_reference const& ref, char* buf, std::size_t sz);
|
||||||
|
|
||||||
// swap pointers of two disk buffer holders.
|
// swap pointers of two disk buffer holders.
|
||||||
void swap(disk_buffer_holder& h) noexcept
|
void swap(disk_buffer_holder& h) noexcept
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(h.m_allocator == m_allocator);
|
TORRENT_ASSERT(h.m_allocator == m_allocator);
|
||||||
std::swap(h.m_buf, m_buf);
|
std::swap(h.m_buf, m_buf);
|
||||||
|
std::swap(h.m_size, m_size);
|
||||||
std::swap(h.m_ref, m_ref);
|
std::swap(h.m_ref, m_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,12 +114,13 @@ namespace libtorrent {
|
||||||
// buffer
|
// buffer
|
||||||
explicit operator bool() const noexcept { return m_buf != nullptr; }
|
explicit operator bool() const noexcept { return m_buf != nullptr; }
|
||||||
|
|
||||||
std::size_t size() const { return 0x4000; }
|
std::size_t size() const { return m_size; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
buffer_allocator_interface* m_allocator;
|
buffer_allocator_interface* m_allocator;
|
||||||
char* m_buf;
|
char* m_buf;
|
||||||
|
std::size_t m_size;
|
||||||
aux::block_cache_reference m_ref;
|
aux::block_cache_reference m_ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1670,10 +1670,11 @@ int block_cache::copy_from_piece(cached_piece_entry* const pe
|
||||||
// make sure it didn't wrap
|
// make sure it didn't wrap
|
||||||
TORRENT_PIECE_ASSERT(pe->refcount > 0, pe);
|
TORRENT_PIECE_ASSERT(pe->refcount > 0, pe);
|
||||||
int const blocks_per_piece = (j->storage->files().piece_length() + block_size() - 1) / block_size();
|
int const blocks_per_piece = (j->storage->files().piece_length() + block_size() - 1) / block_size();
|
||||||
|
TORRENT_ASSERT(block_offset < 0x4000);
|
||||||
j->argument = disk_buffer_holder(allocator
|
j->argument = disk_buffer_holder(allocator
|
||||||
, aux::block_cache_reference{ j->storage->storage_index()
|
, aux::block_cache_reference{ j->storage->storage_index()
|
||||||
, static_cast<int>(pe->piece) * blocks_per_piece + start_block}
|
, static_cast<int>(pe->piece) * blocks_per_piece + start_block}
|
||||||
, bl.buf + (j->d.io.offset & (block_size() - 1)));
|
, bl.buf + block_offset, static_cast<std::size_t>(0x4000 - block_offset));
|
||||||
j->storage->inc_refcount();
|
j->storage->inc_refcount();
|
||||||
|
|
||||||
++m_send_buffer_blocks;
|
++m_send_buffer_blocks;
|
||||||
|
@ -1690,14 +1691,13 @@ int block_cache::copy_from_piece(cached_piece_entry* const pe
|
||||||
}
|
}
|
||||||
|
|
||||||
j->argument = disk_buffer_holder(allocator
|
j->argument = disk_buffer_holder(allocator
|
||||||
, allocate_buffer("send buffer"));
|
, allocate_buffer("send buffer"), 0x4000);
|
||||||
if (!boost::get<disk_buffer_holder>(j->argument)) return -2;
|
if (!boost::get<disk_buffer_holder>(j->argument)) return -2;
|
||||||
|
|
||||||
while (size > 0)
|
while (size > 0)
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_ASSERT(pe->blocks[block].buf, pe);
|
TORRENT_PIECE_ASSERT(pe->blocks[block].buf, pe);
|
||||||
int to_copy = (std::min)(block_size()
|
int to_copy = std::min(block_size() - block_offset, size);
|
||||||
- block_offset, size);
|
|
||||||
std::memcpy(boost::get<disk_buffer_holder>(j->argument).get()
|
std::memcpy(boost::get<disk_buffer_holder>(j->argument).get()
|
||||||
+ buffer_offset
|
+ buffer_offset
|
||||||
, pe->blocks[block].buf + block_offset
|
, pe->blocks[block].buf + block_offset
|
||||||
|
|
|
@ -36,8 +36,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace libtorrent {
|
namespace libtorrent {
|
||||||
|
|
||||||
disk_buffer_holder::disk_buffer_holder(buffer_allocator_interface& alloc, char* buf) noexcept
|
disk_buffer_holder::disk_buffer_holder(buffer_allocator_interface& alloc
|
||||||
: m_allocator(&alloc), m_buf(buf), m_ref()
|
, char* buf, std::size_t sz) noexcept
|
||||||
|
: m_allocator(&alloc), m_buf(buf), m_size(sz), m_ref()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
disk_buffer_holder& disk_buffer_holder::operator=(disk_buffer_holder&& h) noexcept
|
disk_buffer_holder& disk_buffer_holder::operator=(disk_buffer_holder&& h) noexcept
|
||||||
|
@ -48,7 +49,7 @@ namespace libtorrent {
|
||||||
}
|
}
|
||||||
|
|
||||||
disk_buffer_holder::disk_buffer_holder(disk_buffer_holder&& h) noexcept
|
disk_buffer_holder::disk_buffer_holder(disk_buffer_holder&& h) noexcept
|
||||||
: m_allocator(h.m_allocator), m_buf(h.m_buf), m_ref(h.m_ref)
|
: m_allocator(h.m_allocator), m_buf(h.m_buf), m_size(h.m_size), m_ref(h.m_ref)
|
||||||
{
|
{
|
||||||
// we own this buffer now
|
// we own this buffer now
|
||||||
h.m_buf = nullptr;
|
h.m_buf = nullptr;
|
||||||
|
@ -56,23 +57,26 @@ namespace libtorrent {
|
||||||
}
|
}
|
||||||
|
|
||||||
disk_buffer_holder::disk_buffer_holder(buffer_allocator_interface& alloc
|
disk_buffer_holder::disk_buffer_holder(buffer_allocator_interface& alloc
|
||||||
, aux::block_cache_reference const& ref, char* buf) noexcept
|
, aux::block_cache_reference const& ref, char* buf
|
||||||
: m_allocator(&alloc), m_buf(buf), m_ref(ref)
|
, std::size_t sz) noexcept
|
||||||
|
: m_allocator(&alloc), m_buf(buf), m_size(sz), m_ref(ref)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void disk_buffer_holder::reset(aux::block_cache_reference const& ref, char* buf)
|
void disk_buffer_holder::reset(aux::block_cache_reference const& ref, char* buf, std::size_t const sz)
|
||||||
{
|
{
|
||||||
if (m_ref.cookie != aux::block_cache_reference::none) m_allocator->reclaim_blocks(m_ref);
|
if (m_ref.cookie != aux::block_cache_reference::none) m_allocator->reclaim_blocks(m_ref);
|
||||||
else if (m_buf) m_allocator->free_disk_buffer(m_buf);
|
else if (m_buf) m_allocator->free_disk_buffer(m_buf);
|
||||||
m_buf = buf;
|
m_buf = buf;
|
||||||
|
m_size = sz;
|
||||||
m_ref = ref;
|
m_ref = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disk_buffer_holder::reset(char* const buf)
|
void disk_buffer_holder::reset(char* const buf, std::size_t const sz)
|
||||||
{
|
{
|
||||||
if (m_ref.cookie != aux::block_cache_reference::none) m_allocator->reclaim_blocks(m_ref);
|
if (m_ref.cookie != aux::block_cache_reference::none) m_allocator->reclaim_blocks(m_ref);
|
||||||
else if (m_buf) m_allocator->free_disk_buffer(m_buf);
|
else if (m_buf) m_allocator->free_disk_buffer(m_buf);
|
||||||
m_buf = buf;
|
m_buf = buf;
|
||||||
|
m_size = sz;
|
||||||
m_ref = aux::block_cache_reference();
|
m_ref = aux::block_cache_reference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +85,7 @@ namespace libtorrent {
|
||||||
TORRENT_ASSERT(m_ref.cookie == aux::block_cache_reference::none);
|
TORRENT_ASSERT(m_ref.cookie == aux::block_cache_reference::none);
|
||||||
char* ret = m_buf;
|
char* ret = m_buf;
|
||||||
m_buf = nullptr;
|
m_buf = nullptr;
|
||||||
|
m_size = 0;
|
||||||
m_ref = aux::block_cache_reference();
|
m_ref = aux::block_cache_reference();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1231,7 +1231,7 @@ constexpr disk_job_flags_t disk_interface::cache_hit;
|
||||||
|
|
||||||
status_t disk_io_thread::do_uncached_read(disk_io_job* j)
|
status_t disk_io_thread::do_uncached_read(disk_io_job* j)
|
||||||
{
|
{
|
||||||
j->argument = disk_buffer_holder(*this, m_disk_cache.allocate_buffer("send buffer"));
|
j->argument = disk_buffer_holder(*this, m_disk_cache.allocate_buffer("send buffer"), 0x4000);
|
||||||
auto& buffer = boost::get<disk_buffer_holder>(j->argument);
|
auto& buffer = boost::get<disk_buffer_holder>(j->argument);
|
||||||
if (buffer.get() == nullptr)
|
if (buffer.get() == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -1583,7 +1583,7 @@ constexpr disk_job_flags_t disk_interface::cache_hit;
|
||||||
j->piece = r.piece;
|
j->piece = r.piece;
|
||||||
j->d.io.offset = r.start;
|
j->d.io.offset = r.start;
|
||||||
j->d.io.buffer_size = std::uint16_t(r.length);
|
j->d.io.buffer_size = std::uint16_t(r.length);
|
||||||
j->argument = disk_buffer_holder(*this, nullptr);
|
j->argument = disk_buffer_holder(*this, nullptr, 0);
|
||||||
j->flags = flags;
|
j->flags = flags;
|
||||||
j->callback = std::move(handler);
|
j->callback = std::move(handler);
|
||||||
|
|
||||||
|
@ -1688,7 +1688,7 @@ constexpr disk_job_flags_t disk_interface::cache_hit;
|
||||||
TORRENT_ASSERT(r.length <= 16 * 1024);
|
TORRENT_ASSERT(r.length <= 16 * 1024);
|
||||||
|
|
||||||
bool exceeded = false;
|
bool exceeded = false;
|
||||||
disk_buffer_holder buffer(*this, m_disk_cache.allocate_buffer(exceeded, o, "receive buffer"));
|
disk_buffer_holder buffer(*this, m_disk_cache.allocate_buffer(exceeded, o, "receive buffer"), 0x4000);
|
||||||
if (!buffer) aux::throw_ex<std::bad_alloc>();
|
if (!buffer) aux::throw_ex<std::bad_alloc>();
|
||||||
std::memcpy(buffer.get(), buf, aux::numeric_cast<std::size_t>(r.length));
|
std::memcpy(buffer.get(), buf, aux::numeric_cast<std::size_t>(r.length));
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ static void nop() {}
|
||||||
wj.d.io.offset = (b) * 0x4000; \
|
wj.d.io.offset = (b) * 0x4000; \
|
||||||
wj.d.io.buffer_size = 0x4000; \
|
wj.d.io.buffer_size = 0x4000; \
|
||||||
wj.piece = piece_index_t(p); \
|
wj.piece = piece_index_t(p); \
|
||||||
wj.argument = disk_buffer_holder(alloc, bc.allocate_buffer("write-test")); \
|
wj.argument = disk_buffer_holder(alloc, bc.allocate_buffer("write-test"), 0x4000); \
|
||||||
pe = bc.add_dirty_block(&wj)
|
pe = bc.add_dirty_block(&wj)
|
||||||
|
|
||||||
#define READ_BLOCK(p, b, r) \
|
#define READ_BLOCK(p, b, r) \
|
||||||
|
@ -149,7 +149,7 @@ static void nop() {}
|
||||||
rj.d.io.buffer_size = 0x4000; \
|
rj.d.io.buffer_size = 0x4000; \
|
||||||
rj.piece = piece_index_t(p); \
|
rj.piece = piece_index_t(p); \
|
||||||
rj.storage = pm; \
|
rj.storage = pm; \
|
||||||
rj.argument = disk_buffer_holder(alloc, nullptr); \
|
rj.argument = disk_buffer_holder(alloc, nullptr, 0); \
|
||||||
ret = bc.try_read(&rj, alloc)
|
ret = bc.try_read(&rj, alloc)
|
||||||
|
|
||||||
#define FLUSH(flushing) \
|
#define FLUSH(flushing) \
|
||||||
|
@ -444,7 +444,7 @@ void test_unaligned_read()
|
||||||
rj.d.io.buffer_size = 0x4000;
|
rj.d.io.buffer_size = 0x4000;
|
||||||
rj.piece = piece_index_t(0);
|
rj.piece = piece_index_t(0);
|
||||||
rj.storage = pm;
|
rj.storage = pm;
|
||||||
rj.argument = disk_buffer_holder(alloc, nullptr);
|
rj.argument = disk_buffer_holder(alloc, nullptr, 0);
|
||||||
ret = bc.try_read(&rj, alloc);
|
ret = bc.try_read(&rj, alloc);
|
||||||
|
|
||||||
// unaligned reads copies the data into a new buffer
|
// unaligned reads copies the data into a new buffer
|
||||||
|
|
Loading…
Reference in New Issue