Skip to content

Fuzz fail new #1164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 51 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
16aa7cf
add fuzz_fail file
phlptp May 17, 2025
8b90a54
fix the fuzz fail
phlptp May 17, 2025
444f415
add fuzz_fail file
phlptp May 17, 2025
e1e337e
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
9389b30
add fuzz_fail file
phlptp May 18, 2025
c567983
move fuzzer fail
phlptp May 18, 2025
1ff0174
handle carriage return properly
phlptp May 18, 2025
90acdbb
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
7bb012f
try to add more debug output to the tests
phlptp May 18, 2025
bf65860
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
0b4d4cc
try to catch a few other carriage returns
phlptp May 18, 2025
f6fb11a
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
e87e040
add debugging output
phlptp May 18, 2025
b716cdc
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
3eed508
tune the debugging output
phlptp May 18, 2025
38301ac
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
2775a90
more debugging
phlptp May 18, 2025
3dcc9a9
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
3d0fb85
add more debugging output
phlptp May 18, 2025
8464c0d
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
0e9fedd
add fuzz_fail file7
phlptp May 18, 2025
3eb8dee
try adding a fuzz fail test
phlptp May 18, 2025
d2e276c
fix clang tidy issue
phlptp May 18, 2025
49cd534
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
300816e
try another tweak
phlptp May 18, 2025
d47f501
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
a90b5fb
add fuzz_fail file8
phlptp May 18, 2025
bb07eb2
handle custom options better for configurable modifier
phlptp May 18, 2025
eb4ca0c
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
82d20d7
add fuzz_fail file9
phlptp May 18, 2025
ca31efa
string control for binary strings
phlptp May 18, 2025
e2f0b8b
style: pre-commit.ci fixes
pre-commit-ci[bot] May 18, 2025
43856cc
add check for invalid configurations
phlptp May 19, 2025
2964902
style: pre-commit.ci fixes
pre-commit-ci[bot] May 19, 2025
07005f9
use incorrect construction instead of invalid error
phlptp May 19, 2025
35cd209
add fuzz_fail file9
phlptp May 19, 2025
59713f3
rework the fuzzing tests a bit
phlptp May 19, 2025
cd2425b
style: pre-commit.ci fixes
pre-commit-ci[bot] May 19, 2025
e04b282
add fuzz_fail file11
phlptp May 19, 2025
c21921d
add detection for duplication positional only options that have diffe…
phlptp May 19, 2025
e4e5dc6
style: pre-commit.ci fixes
pre-commit-ci[bot] May 19, 2025
2929ffe
add fuzz_fail file11
phlptp May 19, 2025
818951a
properly handle reversed arguments in config files.
phlptp May 20, 2025
c39a005
style: pre-commit.ci fixes
pre-commit-ci[bot] May 20, 2025
ba4a6a0
add fuzz_fail file12
phlptp May 20, 2025
c80a729
add flag checks on positional arguments
phlptp May 21, 2025
413e662
style: pre-commit.ci fixes
pre-commit-ci[bot] May 21, 2025
4195660
add fuzz_fail file12
phlptp May 21, 2025
50e90e9
fix seg fault possibility
phlptp May 21, 2025
b200e34
style: pre-commit.ci fixes
pre-commit-ci[bot] May 21, 2025
5a35a80
clang-tidy fixes
phlptp May 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions fuzz/cli11_app_fuzz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
std::string parseString(reinterpret_cast<const char *>(Data), Size);

CLI::FuzzApp fuzzdata;
CLI::FuzzApp fuzzdata2;

auto app = fuzzdata.generateApp();
auto app2 = fuzzdata2.generateApp();
std::size_t pstring_start{0};
try {
pstring_start = fuzzdata.add_custom_options(app.get(), parseString);
Expand All @@ -40,17 +39,21 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// this just indicates we caught an error known by CLI
return 0; // Non-zero return values are reserved for future use.
}
// should be able to write the config to a file and read from it again
std::string configOut = app->config_to_str();
app->clear();
std::stringstream out(configOut);
if(pstring_start > 0) {
fuzzdata2.add_custom_options(app2.get(), parseString);
}
app2->parse_from_stream(out);
auto result = fuzzdata2.compare(fuzzdata);
if(!result) {
throw CLI::ValidationError("fuzzer", "file input results don't match parse results");
if(fuzzdata.support_config_file_only()) {
CLI::FuzzApp fuzzdata2;
auto app2 = fuzzdata2.generateApp();
// should be able to write the config to a file and read from it again
std::string configOut = app->config_to_str();
std::stringstream out(configOut);
if(pstring_start > 0) {
fuzzdata2.add_custom_options(app2.get(), parseString);
}
app2->parse_from_stream(out);
auto result = fuzzdata2.compare(fuzzdata);
if(!result) {
throw CLI::ValidationError("fuzzer", "file input results don't match parse results");
}
}

return 0;
}
87 changes: 76 additions & 11 deletions fuzz/fuzzApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "fuzzApp.hpp"
#include <algorithm>
#include <iostream>

namespace CLI {
/*
Expand Down Expand Up @@ -151,7 +152,27 @@ std::shared_ptr<CLI::App> FuzzApp::generateApp() {
return fApp;
}

bool FuzzApp::compare(const FuzzApp &other) const {
static void print_string_comparison(const std::string &s1,
const std::string &s2,
const std::string &prefix,
const std::string &s1name,
const std::string &s2name) {
for(size_t jj = 0; jj < (std::max)(s1.size(), s2.size()); ++jj) {
if(jj >= s1.size()) {
std::cout << prefix << ":" << s1name << "[" << jj << "] = [empty], " << s2name << "[" << jj
<< "]=" << static_cast<int>(s2[jj]) << '\n';
} else if(jj >= s2.size()) {
std::cout << prefix << ":" << s1name << "[" << jj << "]=" << static_cast<int>(s1[jj]) << ", " << s2name
<< "[" << jj << "]=[empty] \n";
} else if(s1[jj] != s2[jj]) {
std::cout << "-->" << prefix << ":" << s1name << "[" << jj << "]=" << static_cast<int>(s1[jj]) << ", "
<< s2name << "[" << jj << "]=" << static_cast<int>(s2[jj]) << '\n';
} else {
std::cout << prefix << ":" << s1name << "[" << jj << "]=" << static_cast<int>(s1[jj]) << '\n';
}
}
}
bool FuzzApp::compare(const FuzzApp &other, bool print_error) const {
if(val32 != other.val32) {
return false;
}
Expand Down Expand Up @@ -291,6 +312,20 @@ bool FuzzApp::compare(const FuzzApp &other) const {
std::vector<std::string> res = vstrD;
std::reverse(res.begin(), res.end());
if(res != other.vstrD) {
if(print_error) {
if(res.size() != other.vstrD.size()) {
std::cout << "size is different vstrD.size()=" << res.size()
<< " other.vstrD.size=" << other.vstrD.size() << '\n';
} else {
for(size_t ii = 0; ii < res.size(); ++ii) {
print_string_comparison(res[ii],
other.vstrD[ii],
std::string("string[") + std::to_string(ii) + ']',
"vstrD",
"other.vstrD");
}
}
}
return false;
}
}
Expand All @@ -311,17 +346,28 @@ bool FuzzApp::compare(const FuzzApp &other) const {
return false;
}
for(std::size_t ii = 0; ii < custom_string_options.size(); ++ii) {
if(*custom_string_options[ii] != *other.custom_string_options[ii]) {
return false;
if(custom_string_options[ii]->first != other.custom_string_options[ii]->first) {
if(custom_string_options[ii]->second) {
if(print_error) {
print_string_comparison(custom_string_options[ii]->first,
other.custom_string_options[ii]->first,
std::string("custom_string[") + std::to_string(ii) + ']',
"c1",
"other.c1");
}
return false;
}
}
}
// now test custom vector_options
if(custom_vector_options.size() != other.custom_vector_options.size()) {
return false;
}
for(std::size_t ii = 0; ii < custom_vector_options.size(); ++ii) {
if(*custom_vector_options[ii] != *other.custom_vector_options[ii]) {
return false;
if(custom_vector_options[ii]->first != other.custom_vector_options[ii]->first) {
if(custom_vector_options[ii]->second) {
return false;
}
}
}
return true;
Expand Down Expand Up @@ -447,11 +493,17 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri
break;
}
std::string name = description_string.substr(header_close + 1, end_option - header_close - 1);
custom_string_options.push_back(std::make_shared<std::string>());
auto *opt = app->add_option(name, *(custom_string_options.back()));
custom_string_options.push_back(std::make_shared<std::pair<std::string, bool>>("", true));
auto *opt = app->add_option(name, custom_string_options.back()->first);
if(header_close > current_index + 19) {
std::string attributes = description_string.substr(current_index + 8, header_close - 8 - current_index);
modify_option(opt, attributes);
if(!opt->get_configurable()) {
custom_string_options.back()->second = false;
if(opt->get_required()) {
non_config_required = true;
}
}
}

current_index = end_option + 9;
Expand All @@ -465,12 +517,18 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri
break;
}
std::string name = description_string.substr(header_close + 1, end_option - header_close - 1);
custom_string_options.push_back(std::make_shared<std::string>());
auto *opt = app->add_option(name, *(custom_string_options.back()));
custom_string_options.push_back(std::make_shared<std::pair<std::string, bool>>("", true));
auto *opt = app->add_option(name, custom_string_options.back()->first);

if(header_close > current_index + 17) {
std::string attributes = description_string.substr(current_index + 6, header_close - 6 - current_index);
modify_option(opt, attributes);
if(!opt->get_configurable()) {
custom_string_options.back()->second = false;
if(opt->get_required()) {
non_config_required = true;
}
}
}
current_index = end_option + 7;
} else if(description_string.compare(current_index, 7, "<vector") == 0) {
Expand All @@ -483,11 +541,18 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri
break;
}
std::string name = description_string.substr(header_close + 1, end_option - header_close - 1);
custom_vector_options.push_back(std::make_shared<std::vector<std::string>>());
auto *opt = app->add_option(name, *(custom_vector_options.back()));
custom_vector_options.push_back(std::make_shared<std::pair<std::vector<std::string>, bool>>());
custom_vector_options.back()->second = true;
auto *opt = app->add_option(name, custom_vector_options.back()->first);
if(header_close > current_index + 19) {
std::string attributes = description_string.substr(current_index + 8, header_close - 8 - current_index);
modify_option(opt, attributes);
if(!opt->get_configurable()) {
custom_vector_options.back()->second = false;
if(opt->get_required()) {
non_config_required = true;
}
}
}
current_index = end_option + 9;
} else {
Expand Down
12 changes: 8 additions & 4 deletions fuzz/fuzzApp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ class FuzzApp {
/** generate a fuzzing application with a bunch of different interfaces*/
std::shared_ptr<CLI::App> generateApp();
/** compare two fuzz apps for equality*/
CLI11_NODISCARD bool compare(const FuzzApp &other) const;
CLI11_NODISCARD bool compare(const FuzzApp &other, bool print_error = false) const;
/** generate additional options based on a string config*/
std::size_t add_custom_options(CLI::App *app, const std::string &description_string);
/** modify an option based on string*/
void modify_option(CLI::Option *opt, const std::string &modifier);
static void modify_option(CLI::Option *opt, const std::string &modifier);

CLI11_NODISCARD bool support_config_file_only() const { return !non_config_required; }
int32_t val32{0};
int16_t val16{0};
int8_t val8{0};
Expand Down Expand Up @@ -121,7 +122,10 @@ class FuzzApp {
std::vector<std::string> vstrF{};
std::string mergeBuffer{};
std::vector<std::string> validator_strings{};
std::vector<std::shared_ptr<std::string>> custom_string_options{};
std::vector<std::shared_ptr<std::vector<std::string>>> custom_vector_options{};
std::vector<std::shared_ptr<std::pair<std::string, bool>>> custom_string_options{};
std::vector<std::shared_ptr<std::pair<std::vector<std::string>, bool>>> custom_vector_options{};

private:
bool non_config_required{false};
};
} // namespace CLI
3 changes: 3 additions & 0 deletions include/CLI/App.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,9 @@ class App {
/// Fill in a single config option
bool _parse_single_config(const ConfigItem &item, std::size_t level = 0);

/// @brief store the results for a flag like option
bool _add_flag_like_result(Option *op, const ConfigItem &item, const std::vector<std::string> &inputs);

/// Parse "one" argument (some may eat more than one), delegate to parent if fails, add to missing if missing
/// from main return false if the parse has failed and needs to return to parent
bool _parse_single(std::vector<std::string> &args, bool &positional_only);
Expand Down
2 changes: 1 addition & 1 deletion include/CLI/StringTools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ CLI11_INLINE std::string add_escaped_characters(const std::string &str);
CLI11_INLINE std::string remove_escaped_characters(const std::string &str);

/// generate a string with all non printable characters escaped to hex codes
CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape);
CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force = false);

CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string);

Expand Down
Loading
Loading