From a1f299571667057e793392249691ac4d3b5f3aeb Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 23 Jul 2018 08:43:56 +0200 Subject: [PATCH] add piece index range checks on have_piece() and read_piece() --- include/libtorrent/torrent.hpp | 9 +++++ src/torrent.cpp | 18 +++++++-- src/torrent_handle.cpp | 2 +- test/test_torrent.cpp | 73 ++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 4 deletions(-) diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 9c98c7986..746c1e08a 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -777,6 +777,15 @@ namespace libtorrent { return m_picker->have_piece(index); } + // returns true if we have downloaded the given piece + bool user_have_piece(piece_index_t index) const + { + if (!valid_metadata()) return false; + if (index < piece_index_t{0} || index >= m_torrent_file->end_piece()) return false; + if (!has_picker()) return m_have_all; + return m_picker->have_piece(index); + } + // returns true if we have downloaded the given piece bool has_piece_passed(piece_index_t index) const { diff --git a/src/torrent.cpp b/src/torrent.cpp index 1054ed8eb..e633b3311 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -830,11 +830,23 @@ bool is_downloading_state(int const st) void torrent::read_piece(piece_index_t const piece) { + error_code ec; if (m_abort || m_deleted) { - // failed - m_ses.alerts().emplace_alert( - get_handle(), piece, error_code(boost::system::errc::operation_canceled, generic_category())); + ec.assign(boost::system::errc::operation_canceled, generic_category()); + } + else if (!valid_metadata()) + { + ec.assign(errors::no_metadata, libtorrent_category()); + } + else if (piece < piece_index_t{0} || piece >= m_torrent_file->end_piece()) + { + ec.assign(errors::invalid_piece_index, libtorrent_category()); + } + + if (ec) + { + m_ses.alerts().emplace_alert(get_handle(), piece, ec); return; } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 563579695..7d53470e8 100644 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -664,7 +664,7 @@ namespace libtorrent { bool torrent_handle::have_piece(piece_index_t piece) const { - return sync_call_ret(false, &torrent::have_piece, piece); + return sync_call_ret(false, &torrent::user_have_piece, piece); } storage_interface* torrent_handle::get_storage_impl() const diff --git a/test/test_torrent.cpp b/test/test_torrent.cpp index 8707bb5de..7271523d6 100644 --- a/test/test_torrent.cpp +++ b/test/test_torrent.cpp @@ -618,3 +618,76 @@ TORRENT_TEST(test_move_storage_no_metadata) TEST_EQUAL(h.status().save_path, complete("save_path_1")); } + +TORRENT_TEST(test_have_piece_no_metadata) +{ + lt::session ses(settings()); + error_code ec; + add_torrent_params p = parse_magnet_uri("magnet?xt=urn:btih:abababababababababababababababababababab", ec); + p.save_path = "save_path"; + torrent_handle h = ses.add_torrent(p); + + TEST_EQUAL(h.have_piece(piece_index_t{-1}), false); + TEST_EQUAL(h.have_piece(piece_index_t{0}), false); + TEST_EQUAL(h.have_piece(piece_index_t{100}), false); +} + +TORRENT_TEST(test_have_piece_out_of_range) +{ + lt::session ses(settings()); + error_code ec; + + add_torrent_params p; + static std::array const file_sizes{{100000, 100000}}; + int const piece_size = 0x8000; + p.ti = make_torrent(file_sizes, piece_size); + p.save_path = "save_path"; + p.flags |= torrent_flags::seed_mode; + torrent_handle h = ses.add_torrent(p); + + TEST_EQUAL(h.have_piece(piece_index_t{-1}), false); + TEST_EQUAL(h.have_piece(piece_index_t{0}), true); + TEST_EQUAL(h.have_piece(piece_index_t{100}), false); +} + +TORRENT_TEST(test_read_piece_no_metadata) +{ + lt::session ses(settings()); + error_code ec; + add_torrent_params p = parse_magnet_uri("magnet?xt=urn:btih:abababababababababababababababababababab", ec); + p.save_path = "save_path"; + torrent_handle h = ses.add_torrent(p); + + h.read_piece(piece_index_t{-1}); + + alert const* a = wait_for_alert(ses, read_piece_alert::alert_type, "read_piece_alert"); + TEST_CHECK(a); + if (auto* rp = alert_cast(a)) + { + TEST_CHECK(rp->error == error_code(lt::errors::no_metadata, lt::libtorrent_category())); + } +} + +TORRENT_TEST(test_read_piece_out_of_range) +{ + lt::session ses(settings()); + error_code ec; + + add_torrent_params p; + static std::array const file_sizes{{100000, 100000}}; + int const piece_size = 0x8000; + p.ti = make_torrent(file_sizes, piece_size); + p.save_path = "save_path"; + p.flags |= torrent_flags::seed_mode; + torrent_handle h = ses.add_torrent(p); + + h.read_piece(piece_index_t{-1}); + + alert const* a = wait_for_alert(ses, read_piece_alert::alert_type, "read_piece_alert"); + TEST_CHECK(a); + if (auto* rp = alert_cast(a)) + { + TEST_CHECK(rp->error == error_code(lt::errors::invalid_piece_index + , lt::libtorrent_category())); + } +}