From 44479bcca30ba9f634adb6f613490255888d69e5 Mon Sep 17 00:00:00 2001 From: d-komarov Date: Sat, 21 Apr 2018 19:35:55 +0300 Subject: [PATCH] Fix storage initialization (#2944) If `default_storage::has_any_file` fails during fastresume data check, `piece_manager::check_no_fastresume` will skip storage initialization. In such case, any storage operation that require part file will cause an application crash. --- src/assert.cpp | 4 ++++ src/storage.cpp | 11 +---------- test/test_storage.cpp | 31 +++++++++++++++++++++++++------ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/assert.cpp b/src/assert.cpp index 4bd029498..6858d7d50 100644 --- a/src/assert.cpp +++ b/src/assert.cpp @@ -352,10 +352,14 @@ TORRENT_EXPORT void assert_fail(char const* expr, int line // if production asserts are defined, don't abort, just print the error #ifndef TORRENT_PRODUCTION_ASSERTS + #ifdef _MSC_VER + __debugbreak(); + #else // send SIGINT to the current process // to break into the debugger raise(SIGABRT); abort(); + #endif #endif } diff --git a/src/storage.cpp b/src/storage.cpp index 3641c51ff..e444b7f3a 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1792,19 +1792,10 @@ namespace libtorrent int piece_manager::check_no_fastresume(storage_error& ec) { - bool has_files = false; if (!m_storage->settings().get_bool(settings_pack::no_recheck_incomplete_resume)) { storage_error se; - has_files = m_storage->has_any_file(se); - - if (se) - { - ec = se; - return fatal_disk_error; - } - - if (has_files) + if (m_storage->has_any_file(se)) { // always initialize the storage int ret = check_init_storage(ec); diff --git a/test/test_storage.cpp b/test/test_storage.cpp index f2eb75dd1..9aa4f5fc9 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -415,6 +415,18 @@ void test_rename(std::string const& test_path) TEST_EQUAL(s->files().file_path(0), "new_filename"); } +struct test_error_storage : default_storage +{ + test_error_storage(storage_params const& params) : default_storage(params) {}; + + bool has_any_file(storage_error& ec) TORRENT_FINAL + { + ec.ec = make_error_code(boost::system::errc::permission_denied); + ec.operation = storage_error::stat; + return false; + } +}; + void test_check_files(std::string const& test_path , libtorrent::storage_mode_t storage_mode , bool unbuffered) @@ -458,22 +470,21 @@ void test_check_files(std::string const& test_path bencode(std::back_inserter(buf), t.generate()); info = boost::make_shared(&buf[0], buf.size(), boost::ref(ec), 0); - aux::session_settings set; file_pool fp; boost::asio::io_service ios; counters cnt; disk_io_thread io(ios, cnt, NULL); io.set_num_threads(1); - disk_buffer_pool dp(16 * 1024, ios, boost::bind(&nop)); + std::vector prio(info->num_files(), 0); storage_params p; p.files = &fs; p.path = test_path; p.pool = &fp; p.mode = storage_mode; + p.priorities = &prio; boost::shared_ptr dummy; - boost::shared_ptr pm = boost::make_shared(new default_storage(p), dummy, &fs); - libtorrent::mutex lock; + boost::shared_ptr pm = boost::make_shared(new test_error_storage(p), dummy, &fs); bool done = false; bdecode_node frd; @@ -481,10 +492,18 @@ void test_check_files(std::string const& test_path io.async_check_fastresume(pm.get(), &frd, links , boost::bind(&on_check_resume_data, _1, &done)); io.submit_jobs(); - ios.reset(); run_until(ios, done); - io.set_num_threads(0); + for (int i = 0; i < info->num_pieces(); ++i) + { + done = false; + io.async_hash(pm.get(), i, disk_io_job::sequential_access | disk_io_job::volatile_read + , boost::bind(&on_check_resume_data, _1, &done), reinterpret_cast(1)); + io.submit_jobs(); + run_until(ios, done); + } + + io.abort(true); } // TODO: 2 split this test up into smaller parts