Restrict parse value to strtoll with restrictions on input.

This commit is contained in:
rakshasa
2026-09-30 12:01:13 +02:00
committed by Jari Sundell
parent 44d51171e1
commit c5d54fbb97
16 changed files with 440 additions and 60 deletions
+8 -8
View File
@@ -51,6 +51,8 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
rpc/test_command_slot.h \
rpc/test_object_storage.cc \
rpc/test_object_storage.h \
rpc/test_parse.cc \
rpc/test_parse.h \
rpc/test_parse_options.cc \
rpc/test_parse_options.h \
rpc/test_rpc_manager.cc \
@@ -59,6 +61,8 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
src/test_command_dynamic.cc \
src/test_command_dynamic.h \
src/test_command_groups.cc \
src/test_command_groups.h \
src/test_command_ip.cc \
src/test_command_ip.h \
src/test_command_system.cc \
@@ -67,14 +71,10 @@ rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
src/test_command_path.h \
src/test_command_string.cc \
src/test_command_string.h \
src/test_command_throttle.cc \
src/test_command_throttle.h \
src/test_input_path_input.cc \
src/test_input_path_input.h \
src/test_session_commit.cc \
src/test_session_commit.h \
src/test_session_storer.cc \
src/test_session_storer.h \
src/test_command_tracker.cc \
src/test_command_tracker.h \
src/test_download_list.cc \
src/test_download_list.h \
src/test_setup.cc \
src/test_setup.h \
src/test_ui_download_list.cc \
+95
View File
@@ -0,0 +1,95 @@
#include "config.h"
#include "test/rpc/test_parse.h"
#include <cstdint>
#include <limits>
#include "rpc/parse.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestParse);
void
TestParse::test_whole_value_in_range() {
int64_t value = 0;
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("9223372036854775807", &value));
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<int64_t>::max(), value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("-9223372036854775808", &value));
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<int64_t>::min(), value);
}
void
TestParse::test_whole_value_out_of_range() {
int64_t value = 0;
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("9223372036854775808", &value));
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-9223372036854775809", &value));
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("99999999999999999999999999", &value));
}
void
TestParse::test_whole_value_bases() {
int64_t value = 0;
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0x1f", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0X1F", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-0x1f", &value));
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0022", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{022}, value);
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("0028", &value));
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("+022", &value));
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-022", &value));
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("22", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{22}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("1f", &value, 16));
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0x1f", &value, 16));
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("22", &value, 8));
CPPUNIT_ASSERT_EQUAL(int64_t{022}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("022", &value, 8));
CPPUNIT_ASSERT_EQUAL(int64_t{022}, value);
const char* no_digits = "0x";
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow(no_digits, &value));
CPPUNIT_ASSERT_EQUAL(no_digits + 1, rpc::parse_value_nothrow(no_digits, &value));
const char* bad_digits = "0xzz";
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow(bad_digits, &value));
CPPUNIT_ASSERT_EQUAL(bad_digits + 1, rpc::parse_value_nothrow(bad_digits, &value));
}
void
TestParse::test_whole_value_prefixes() {
int64_t value = 0;
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("+5", &value));
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow(" 5 ", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{5}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("5k", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{5120}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("yes", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{1}, value);
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("false", &value));
CPPUNIT_ASSERT_EQUAL(int64_t{0}, value);
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("junk", &value));
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("", &value));
}
+18
View File
@@ -0,0 +1,18 @@
#include "test/helpers/test_fixture.h"
class TestParse : public test_fixture {
CPPUNIT_TEST_SUITE(TestParse);
CPPUNIT_TEST(test_whole_value_in_range);
CPPUNIT_TEST(test_whole_value_out_of_range);
CPPUNIT_TEST(test_whole_value_bases);
CPPUNIT_TEST(test_whole_value_prefixes);
CPPUNIT_TEST_SUITE_END();
public:
void test_whole_value_in_range();
void test_whole_value_out_of_range();
void test_whole_value_bases();
void test_whole_value_prefixes();
};
+65
View File
@@ -0,0 +1,65 @@
#include "config.h"
#include "test/src/test_command_groups.h"
#include <torrent/torrent.h>
#include "control.h"
#include "globals.h"
#include "rpc/parse_commands.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandGroups);
void initialize_command_groups();
static void
call_set(const char* value) {
torrent::Object::list_type args;
args.push_back(torrent::Object(int64_t{0}));
args.push_back(torrent::Object(std::string(value)));
rpc::commands.call_command("choke_group.up.max.set", torrent::Object::create_list_range(args.begin(), args.end()));
}
static int64_t
call_get(const char* key) {
return rpc::commands.call_command(key, torrent::Object(int64_t{0})).as_value();
}
void
TestCommandGroups::setUp() {
torrent::initialize_main_thread();
torrent::initialize();
if (control == nullptr)
control = new Control;
if (!rpc::commands.has("choke_group.up.max.set"))
initialize_command_groups();
}
void
TestCommandGroups::tearDown() {
torrent::cleanup();
}
void
TestCommandGroups::test_max_unchoked_in_range() {
call_set("50");
CPPUNIT_ASSERT_EQUAL(int64_t{50}, call_get("choke_group.up.max"));
CPPUNIT_ASSERT_EQUAL(int64_t{0}, call_get("choke_group.up.max.unlimited"));
call_set("-1");
CPPUNIT_ASSERT_EQUAL(int64_t{1}, call_get("choke_group.up.max.unlimited"));
}
void
TestCommandGroups::test_max_unchoked_out_of_range() {
call_set("50");
CPPUNIT_ASSERT_THROW(call_set("4294967296"), torrent::input_error);
CPPUNIT_ASSERT_EQUAL(int64_t{50}, call_get("choke_group.up.max"));
CPPUNIT_ASSERT_THROW(call_set("-2"), torrent::input_error);
CPPUNIT_ASSERT_EQUAL(int64_t{50}, call_get("choke_group.up.max"));
}
+17
View File
@@ -0,0 +1,17 @@
#include "test/helpers/test_fixture.h"
class TestCommandGroups : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandGroups);
CPPUNIT_TEST(test_max_unchoked_in_range);
CPPUNIT_TEST(test_max_unchoked_out_of_range);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_max_unchoked_in_range();
void test_max_unchoked_out_of_range();
};
+73
View File
@@ -0,0 +1,73 @@
#include "config.h"
#include "test/src/test_command_tracker.h"
#include <torrent/runtime/network_config.h>
#include <torrent/torrent.h>
#include "control.h"
#include "globals.h"
#include "command_helpers.h"
#include "rpc/parse_commands.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandTracker);
void initialize_command_tracker();
static void
call_set(const char* value) {
rpc::commands.call_command("dht.override_port.set", torrent::Object(std::string(value)));
}
static uint16_t
override_port() {
return torrent::runtime::network_config()->override_dht_port();
}
void
TestCommandTracker::setUp() {
torrent::initialize_main_thread();
torrent::initialize();
if (control == nullptr)
control = new Control;
if (!rpc::commands.has("dht.override_port.set"))
initialize_command_tracker();
}
void
TestCommandTracker::tearDown() {
torrent::cleanup();
}
void
TestCommandTracker::test_dht_override_port_in_range() {
call_set("6881");
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, override_port());
call_set("65535");
CPPUNIT_ASSERT_EQUAL(uint16_t{65535}, override_port());
}
void
TestCommandTracker::test_dht_override_port_out_of_range() {
call_set("6881");
CPPUNIT_ASSERT_THROW(call_set("70000"), torrent::input_error);
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, override_port());
CPPUNIT_ASSERT_THROW(call_set("-1"), torrent::input_error);
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, override_port());
}
void
TestCommandTracker::test_checked_port_value() {
CPPUNIT_ASSERT_EQUAL(uint16_t{0}, checked_port_value(0, "test"));
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, checked_port_value(6881, "test"));
CPPUNIT_ASSERT_EQUAL(uint16_t{65535}, checked_port_value(65535, "test"));
CPPUNIT_ASSERT_THROW(checked_port_value(-1, "test"), torrent::input_error);
CPPUNIT_ASSERT_THROW(checked_port_value(65536, "test"), torrent::input_error);
CPPUNIT_ASSERT_THROW(checked_port_value(4294967296, "test"), torrent::input_error);
}
+19
View File
@@ -0,0 +1,19 @@
#include "test/helpers/test_fixture.h"
class TestCommandTracker : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandTracker);
CPPUNIT_TEST(test_dht_override_port_in_range);
CPPUNIT_TEST(test_dht_override_port_out_of_range);
CPPUNIT_TEST(test_checked_port_value);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_dht_override_port_in_range();
void test_dht_override_port_out_of_range();
void test_checked_port_value();
};
+68
View File
@@ -0,0 +1,68 @@
#include "config.h"
#include "test/src/test_download_list.h"
#include <cstdio>
#include <torrent/download.h>
#include <torrent/download_info.h>
#include <torrent/hash_string.h>
#include <torrent/object.h>
#include <torrent/torrent.h>
#include "control.h"
#include "core/download.h"
#include "globals.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestDownloadList);
static std::string
insert_download(core::DownloadList* list) {
torrent::Object info = torrent::Object::create_map();
info.insert_key("name", std::string("test_download_list"));
info.insert_key("length", int64_t{16});
info.insert_key("piece length", int64_t{262144});
info.insert_key("pieces", std::string(20, char(0)));
auto* object = new torrent::Object(torrent::Object::create_map());
object->insert_key("info", info);
auto download = torrent::download_add(object, 0);
list->insert(new core::Download(download));
char buffer[41];
for (unsigned int i = 0; i < torrent::HashString::size_data; i++)
snprintf(buffer + i * 2, 3, "%02x", static_cast<unsigned char>(download.info()->hash()[i]));
return std::string(buffer, 40);
}
void
TestDownloadList::setUp() {
torrent::initialize_main_thread();
torrent::initialize();
if (control == nullptr)
control = new Control;
m_hex = insert_download(&m_list);
}
void
TestDownloadList::tearDown() {
m_list.clear();
torrent::cleanup();
}
void
TestDownloadList::test_find_hex() {
CPPUNIT_ASSERT(m_list.find_hex(m_hex.c_str()) != m_list.end());
}
void
TestDownloadList::test_find_hex_wrong_length() {
CPPUNIT_ASSERT(m_list.find_hex((m_hex + "f").c_str()) == m_list.end());
CPPUNIT_ASSERT(m_list.find_hex((m_hex + m_hex).c_str()) == m_list.end());
CPPUNIT_ASSERT(m_list.find_hex(m_hex.substr(0, 39).c_str()) == m_list.end());
}
+24
View File
@@ -0,0 +1,24 @@
#include <string>
#include "core/download_list.h"
#include "test/helpers/test_fixture.h"
class TestDownloadList : public test_fixture {
CPPUNIT_TEST_SUITE(TestDownloadList);
CPPUNIT_TEST(test_find_hex);
CPPUNIT_TEST(test_find_hex_wrong_length);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_find_hex();
void test_find_hex_wrong_length();
private:
core::DownloadList m_list;
std::string m_hex;
};