From a77ef087d5d59be2d88d4921199e1e911726a517 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Tue, 21 Apr 2020 18:27:11 +0300 Subject: Add libfuzzer test to libconfiguration --- .gitignore | 2 + lib/configuration/configuration.cpp | 101 ++++++++++++++++++++----------- lib/configuration/configuration.h | 3 +- lib/configuration/meson.build | 10 ++- lib/configuration/qt_specialization.h | 2 +- lib/configuration/test/corpus/apple.txt | 1 + lib/configuration/test/corpus/banana.txt | 1 + lib/configuration/test/corpus/orange.txt | 1 + 8 files changed, 84 insertions(+), 37 deletions(-) create mode 100644 lib/configuration/test/corpus/apple.txt create mode 100644 lib/configuration/test/corpus/banana.txt create mode 100644 lib/configuration/test/corpus/orange.txt diff --git a/.gitignore b/.gitignore index f7e29ea..43ad28c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ tools/src/crashhandler/defaults.go .config.old compile_commands.json +lib/configuration/test/corpus + diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp index 01a5080..75f863c 100644 --- a/lib/configuration/configuration.cpp +++ b/lib/configuration/configuration.cpp @@ -7,21 +7,17 @@ */ #include "configuration.h" -#include #include #include #include #include #include -static std::unique_ptr s_conf; - -inline void strip(std::string &value) -{ - value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to(), ' '))); +#ifndef NO_QT_SPEC +#include +#endif - value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to(), ' ')).base(), value.end()); -} +static std::unique_ptr s_conf; Configuration::Configuration() : use_global(true) @@ -32,7 +28,9 @@ Configuration::Configuration() } Configuration::Configuration(std::initializer_list> l) noexcept +#ifndef NO_QT_SPEC : m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString()) +#endif { for(const auto &i : l) { insert_or_assign(i.first, i.second); @@ -48,10 +46,61 @@ void Configuration::read_file(const std::string &location) } } +inline auto strip(std::string &value) +{ + value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to(), ' '))); + value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to(), ' ')).base(), value.end()); + return value; +} + +inline auto parse(const std::string &line, std::string §ion) +{ + struct { + bool pair = false; + std::string key; + std::string value; + } ret; + + if(line[0] == '#' || line.length() == 0) { + return ret; + } + + if(line.front() == '[' && line.back() == ']') { + section = line.substr(1, line.length() - 2) + '/'; + return ret; + } + + const auto pos = line.find_first_of('='); + if(pos == std::string::npos) { + return ret; + } + + ret.key = line.substr(0, pos); + strip(ret.key); + if(ret.key.empty()) { + return ret; + } + ret.key = section + ret.key; + + ret.value = line.substr(pos + 1); + strip(ret.value); + + ret.pair = true; + return ret; +} + +#ifdef FUZZER +extern "C" int LLVMFuzzerTestOneInput(const char *Data, long long Size) +{ + std::string section; + parse(std::string(Data, Size), section); + return 0; +} +#endif + void Configuration::read(std::basic_istream &input) { - std::string line, section, key, value; - std::istringstream is_line; + std::string line, section; while(std::getline(input, line)) { if(line.rfind("@@") == 0) { @@ -60,39 +109,23 @@ void Configuration::read(std::basic_istream &input) } continue; } - if(line[0] == '#' || line.length() == 0) { - continue; - } - - if(line.front() == '[' && line.back() == ']') { - section = line.substr(1, line.length() - 2) + '/'; - continue; - } - - is_line.clear(); - is_line.str(line); - - const auto pos = line.find_first_of('='); - if(pos != std::string::npos) { - key = section + line.substr(0, pos); - value = line.substr(pos + 1); - strip(key); - strip(value); + const auto pair = parse(line, section); + if(pair.pair) { - if(this->count(key) == 0) { + if(this->count(pair.key) == 0) { // no type has been specified for this key, assuming std::string - insert(std::make_pair(key, value)); + insert(std::make_pair(pair.key, pair.value)); continue; } - auto v = at(key); + auto v = at(pair.key); if(std::holds_alternative(v)) { - at(key) = value; + at(pair.key) = pair.value; } else if(std::holds_alternative(v)) { - at(key) = std::stoi(value); + at(pair.key) = std::stoi(pair.value); } else if(std::holds_alternative(v)) { - at(key) = (value == "true"); + at(pair.key) = (pair.value == "true"); } } } diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h index 9816ab7..09c41a0 100644 --- a/lib/configuration/configuration.h +++ b/lib/configuration/configuration.h @@ -9,7 +9,6 @@ #ifndef SMOLBOTE_CONFIGURATION_H #define SMOLBOTE_CONFIGURATION_H -#include #include #include #include @@ -136,7 +135,9 @@ private: const bool use_global = false; }; +#ifndef NO_QT_SPEC #include "qt_specialization.h" +#endif std::ostream &operator<<(std::ostream &out, const Configuration &obj); diff --git a/lib/configuration/meson.build b/lib/configuration/meson.build index 104f046..59ddb7a 100644 --- a/lib/configuration/meson.build +++ b/lib/configuration/meson.build @@ -3,7 +3,7 @@ dep_configuration = declare_dependency( link_with: static_library('configuration', ['configuration.cpp', 'qt_specialization.cpp'], dependencies: dep_qt5) ) -test('configuration', executable('configuration-parser', +test('conf parser', executable('configuration-parser', sources: [ 'test/main.cpp' ], dependencies: [ dep_qt5, dep_catch, dep_configuration ] ), @@ -12,3 +12,11 @@ test('configuration', executable('configuration-parser', workdir: meson.current_source_dir()/'test' ) +if meson.get_compiler('cpp').has_multi_arguments('-g', '-fsanitize=fuzzer') +test('conf fuzzer', executable('configuration-fuzzer', + sources: 'configuration.cpp', + cpp_args: [ '-g', '-fsanitize=fuzzer', '-DNO_QT_SPEC', '-DFUZZER' ], + link_args: [ '-fsanitize=fuzzer' ]), + args: [ '-seed=1', '-max_total_time=24', meson.current_source_dir()/'test/corpus' ] +) +endif diff --git a/lib/configuration/qt_specialization.h b/lib/configuration/qt_specialization.h index ea16fe0..9634261 100644 --- a/lib/configuration/qt_specialization.h +++ b/lib/configuration/qt_specialization.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -12,4 +13,3 @@ template <> callable_when(unconsumed) QAction &Configuration::shortcut(QAction &, const char *) const; template <> callable_when(unconsumed) QKeySequence &Configuration::shortcut(QKeySequence &, const char *) const; - diff --git a/lib/configuration/test/corpus/apple.txt b/lib/configuration/test/corpus/apple.txt new file mode 100644 index 0000000..7b89edb --- /dev/null +++ b/lib/configuration/test/corpus/apple.txt @@ -0,0 +1 @@ +key=value diff --git a/lib/configuration/test/corpus/banana.txt b/lib/configuration/test/corpus/banana.txt new file mode 100644 index 0000000..399727c --- /dev/null +++ b/lib/configuration/test/corpus/banana.txt @@ -0,0 +1 @@ +[section] diff --git a/lib/configuration/test/corpus/orange.txt b/lib/configuration/test/corpus/orange.txt new file mode 100644 index 0000000..308ec1d --- /dev/null +++ b/lib/configuration/test/corpus/orange.txt @@ -0,0 +1 @@ +# comment -- cgit v1.2.1