forked from premiere/premiere-libtorrent
fix infinite loop when parsing torrents whose filenames have zeroes. #2247
This commit is contained in:
parent
fcb9c7b6f3
commit
b70d3efba9
2
AUTHORS
2
AUTHORS
|
@ -14,6 +14,8 @@ Stas Khirman
|
|||
Ryan Norton
|
||||
Andrew Resch
|
||||
|
||||
Thanks to (github user) nervoir for bug reports
|
||||
|
||||
Building and maintainance of the autotools scripts:
|
||||
Michael Wojciechowski
|
||||
Peter Koeleman
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
* fix infinite loop when parsing maliciously crafted torrents
|
||||
* fix invalid read in parse_int in bdecoder
|
||||
* fix issue with very long tracker- and web seed URLs
|
||||
* don't attempt to create empty files on startup, if they already exist
|
||||
|
|
|
@ -103,6 +103,18 @@ namespace libtorrent
|
|||
bool is_i2p_url(std::string const& url);
|
||||
|
||||
#endif
|
||||
|
||||
// this can be used as the hash function in std::unordered_*
|
||||
struct TORRENT_EXTRA_EXPORT string_hash_no_case
|
||||
{ size_t operator()(std::string const& s) const; };
|
||||
|
||||
// these can be used as the comparison functions in std::map and std::set
|
||||
struct TORRENT_EXTRA_EXPORT string_eq_no_case
|
||||
{ bool operator()(std::string const& lhs, std::string const& rhs) const; };
|
||||
|
||||
struct TORRENT_EXTRA_EXPORT string_less_no_case
|
||||
{ bool operator()(std::string const& lhs, std::string const& rhs) const; };
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -277,5 +277,48 @@ namespace libtorrent
|
|||
|
||||
#endif
|
||||
|
||||
std::size_t string_hash_no_case::operator()(std::string const& s) const
|
||||
{
|
||||
size_t ret = 5381;
|
||||
for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
|
||||
ret = (ret * 33) ^ to_lower(*i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool string_eq_no_case::operator()(std::string const& lhs, std::string const& rhs) const
|
||||
{
|
||||
if (lhs.size() != rhs.size()) return false;
|
||||
|
||||
std::string::const_iterator s1 = lhs.begin();
|
||||
std::string::const_iterator s2 = rhs.begin();
|
||||
|
||||
while (s1 != lhs.end() && s2 != rhs.end())
|
||||
{
|
||||
if (to_lower(*s1) != to_lower(*s2)) return false;
|
||||
++s1;
|
||||
++s2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string_less_no_case::operator()(std::string const& lhs, std::string const& rhs) const
|
||||
{
|
||||
std::string::const_iterator s1 = lhs.begin();
|
||||
std::string::const_iterator s2 = rhs.begin();
|
||||
|
||||
while (s1 != lhs.end() && s2 != rhs.end())
|
||||
{
|
||||
char const c1 = to_lower(*s1);
|
||||
char const c2 = to_lower(*s2);
|
||||
if (c1 < c2) return true;
|
||||
if (c1 > c2) return false;
|
||||
++s1;
|
||||
++s2;
|
||||
}
|
||||
|
||||
// this is the tie-breaker
|
||||
return lhs.size() < rhs.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -497,65 +497,6 @@ namespace libtorrent
|
|||
return true;
|
||||
}
|
||||
|
||||
#if TORRENT_HAS_BOOST_UNORDERED
|
||||
struct string_hash_no_case
|
||||
{
|
||||
size_t operator()(std::string const& s) const
|
||||
{
|
||||
char const* s1 = s.c_str();
|
||||
size_t ret = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *s1++))
|
||||
ret = (ret * 33) ^ to_lower(c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct string_eq_no_case
|
||||
{
|
||||
bool operator()(std::string const& lhs, std::string const& rhs) const
|
||||
{
|
||||
char c1, c2;
|
||||
char const* s1 = lhs.c_str();
|
||||
char const* s2 = rhs.c_str();
|
||||
|
||||
while (*s1 != 0 && *s2 != 0)
|
||||
{
|
||||
c1 = to_lower(*s1);
|
||||
c2 = to_lower(*s2);
|
||||
if (c1 != c2) return false;
|
||||
++s1;
|
||||
++s2;
|
||||
}
|
||||
return *s1 == *s2;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
struct string_less_no_case
|
||||
{
|
||||
bool operator()(std::string const& lhs, std::string const& rhs) const
|
||||
{
|
||||
char c1, c2;
|
||||
char const* s1 = lhs.c_str();
|
||||
char const* s2 = rhs.c_str();
|
||||
|
||||
while (*s1 != 0 || *s2 != 0)
|
||||
{
|
||||
c1 = to_lower(*s1);
|
||||
c2 = to_lower(*s2);
|
||||
if (c1 < c2) return true;
|
||||
if (c1 > c2) return false;
|
||||
++s1;
|
||||
++s2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// root_dir is the name of the torrent, unless this is a single file
|
||||
// torrent, in which case it's empty.
|
||||
bool extract_files(bdecode_node const& list, file_storage& target
|
||||
|
|
|
@ -310,3 +310,70 @@ TORRENT_TEST(string)
|
|||
, convert_to_native("foo") + convert_to_native("bar"));
|
||||
}
|
||||
|
||||
TORRENT_TEST(string_hash_no_case)
|
||||
{
|
||||
string_hash_no_case hsh;
|
||||
|
||||
// make sure different strings yield different hashes
|
||||
TEST_CHECK(hsh("ab") != hsh("ba"));
|
||||
|
||||
// make sure case is ignored
|
||||
TEST_EQUAL(hsh("Ab"), hsh("ab"));
|
||||
TEST_EQUAL(hsh("Ab"), hsh("aB"));
|
||||
|
||||
// make sure zeroes in strings are supported
|
||||
TEST_CHECK(hsh(std::string("\0a", 2)) != hsh(std::string("\0b", 2)));
|
||||
TEST_EQUAL(hsh(std::string("\0a", 2)), hsh(std::string("\0a", 2)));
|
||||
}
|
||||
|
||||
TORRENT_TEST(string_eq_no_case)
|
||||
{
|
||||
string_eq_no_case cmp;
|
||||
TEST_CHECK(cmp("ab", "ba") == false);
|
||||
TEST_CHECK(cmp("", ""));
|
||||
TEST_CHECK(cmp("abc", "abc"));
|
||||
|
||||
// make sure different lengths are correctly treated as different
|
||||
TEST_CHECK(cmp("abc", "ab") == false);
|
||||
|
||||
// make sure case is ignored
|
||||
TEST_CHECK(cmp("Ab", "ab"));
|
||||
TEST_CHECK(cmp("Ab", "aB"));
|
||||
|
||||
// make sure zeros are supported
|
||||
TEST_CHECK(cmp(std::string("\0a", 2), std::string("\0b", 2)) == false);
|
||||
TEST_CHECK(cmp(std::string("\0a", 2), std::string("\0a", 2)));
|
||||
}
|
||||
|
||||
TORRENT_TEST(string_less_no_case)
|
||||
{
|
||||
string_less_no_case cmp;
|
||||
// ab < ba
|
||||
TEST_CHECK(cmp("ab", "ba"));
|
||||
TEST_CHECK(cmp("ba", "ab") == false);
|
||||
|
||||
TEST_CHECK(cmp("", "") == false);
|
||||
TEST_CHECK(cmp("", "a"));
|
||||
TEST_CHECK(cmp("abc", "abc") == false);
|
||||
|
||||
// shorter strings come before longer ones
|
||||
TEST_CHECK(cmp("abc", "ab") == false);
|
||||
TEST_CHECK(cmp("ab", "abc"));
|
||||
|
||||
// make sure case is ignored
|
||||
TEST_CHECK(cmp("Ab", "ba"));
|
||||
TEST_CHECK(cmp("Ba", "ab") == false);
|
||||
|
||||
TEST_CHECK(cmp("", "") == false);
|
||||
TEST_CHECK(cmp("", "a"));
|
||||
TEST_CHECK(cmp("abc", "Abc") == false);
|
||||
|
||||
// shorter strings come before longer ones
|
||||
TEST_CHECK(cmp("Abc", "ab") == false);
|
||||
TEST_CHECK(cmp("Ab", "abc"));
|
||||
|
||||
// make sure zeros are supported
|
||||
TEST_CHECK(cmp(std::string("\0a", 2), std::string("\0b", 2)));
|
||||
TEST_CHECK(cmp(std::string("\0a", 2), std::string("\0a", 2)) == false);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue