mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
Fuzz fail (#1097)
fix failing fuzz case involving binary string with a '\x' in it. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
8260578fd2
commit
063b2c911c
@ -29,7 +29,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
|
||||
try {
|
||||
if(pstring_start > 0) {
|
||||
app->parse(parseString.substr(pstring_start, std::string::npos));
|
||||
app->parse(parseString.substr(pstring_start));
|
||||
} else {
|
||||
app->parse(parseString);
|
||||
}
|
||||
|
@ -542,8 +542,9 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string value = detail::ini_join(
|
||||
opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, literalQuote);
|
||||
auto results = opt->reduced_results();
|
||||
std::string value =
|
||||
detail::ini_join(results, arraySeparator, arrayStart, arrayEnd, stringQuote, literalQuote);
|
||||
|
||||
bool isDefault = false;
|
||||
if(value.empty() && default_also) {
|
||||
@ -560,7 +561,16 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
|
||||
}
|
||||
|
||||
if(!value.empty()) {
|
||||
|
||||
if(opt->get_expected_max() > 1 && detail::is_binary_escaped_string(value) && results.size() == 1 &&
|
||||
!results[0].empty()) {
|
||||
if(results[0].front() == '[' && results[0].back() == ']') {
|
||||
// this is a condition which could be misinterpreted
|
||||
results[0].insert(0, 1, results[0].front());
|
||||
results[0].push_back(results[0].back());
|
||||
value = detail::ini_join(
|
||||
results, arraySeparator, arrayStart, arrayEnd, stringQuote, literalQuote);
|
||||
}
|
||||
}
|
||||
if(!opt->get_fnames().empty()) {
|
||||
try {
|
||||
value = opt->get_flag_value(single_name, value);
|
||||
|
@ -665,14 +665,21 @@ CLI11_INLINE int Option::_add_result(std::string &&result, std::vector<std::stri
|
||||
if((allow_extra_args_ || get_expected_max() > 1) && !result.empty() && result.front() == '[' &&
|
||||
result.back() == ']') { // this is now a vector string likely from the default or user entry
|
||||
result.pop_back();
|
||||
|
||||
for(auto &var : CLI::detail::split_up(result.substr(1), ',')) {
|
||||
result.erase(result.begin());
|
||||
bool skipSection{false};
|
||||
for(auto &var : CLI::detail::split_up(result, ',')) {
|
||||
if(var == result) {
|
||||
skipSection = true;
|
||||
break;
|
||||
}
|
||||
if(!var.empty()) {
|
||||
result_count += _add_result(std::move(var), res);
|
||||
}
|
||||
}
|
||||
if(!skipSection) {
|
||||
return result_count;
|
||||
}
|
||||
}
|
||||
if(delimiter_ == '\0') {
|
||||
res.push_back(std::move(result));
|
||||
++result_count;
|
||||
|
@ -433,6 +433,13 @@ CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escap
|
||||
stream << std::hex << static_cast<unsigned int>(static_cast<unsigned char>(c));
|
||||
std::string code = stream.str();
|
||||
escaped_string += std::string("\\x") + (code.size() < 2 ? "0" : "") + code;
|
||||
} else if(c == 'x' || c == 'X') {
|
||||
// need to check for inadvertent binary sequences
|
||||
if(!escaped_string.empty() && escaped_string.back() == '\\') {
|
||||
escaped_string += std::string("\\x") + (c == 'x' ? "78" : "58");
|
||||
} else {
|
||||
escaped_string.push_back(c);
|
||||
}
|
||||
|
||||
} else {
|
||||
escaped_string.push_back(c);
|
||||
|
@ -260,3 +260,33 @@ TEST_CASE("fuzz_config_test1") {
|
||||
CHECK(app->get_option_no_throw("--new_flag") != nullptr);
|
||||
CHECK(app->get_option_no_throw("--new_vector") != nullptr);
|
||||
}
|
||||
|
||||
// this test uses the same tests as above just with a full roundtrip test
|
||||
TEST_CASE("app_roundtrip_custom") {
|
||||
CLI::FuzzApp fuzzdata;
|
||||
CLI::FuzzApp fuzzdata2;
|
||||
auto app = fuzzdata.generateApp();
|
||||
auto app2 = fuzzdata2.generateApp();
|
||||
int index = GENERATE(range(1, 3));
|
||||
std::string optionString, flagString;
|
||||
auto parseData = loadFailureFile("round_trip_custom", index);
|
||||
std::size_t pstring_start{0};
|
||||
pstring_start = fuzzdata.add_custom_options(app.get(), parseData);
|
||||
|
||||
if(pstring_start > 0) {
|
||||
app->parse(parseData.substr(pstring_start));
|
||||
} else {
|
||||
app->parse(parseData);
|
||||
}
|
||||
|
||||
// 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(), parseData);
|
||||
}
|
||||
app2->parse_from_stream(out);
|
||||
auto result = fuzzdata2.compare(fuzzdata);
|
||||
CHECK(result);
|
||||
}
|
||||
|
@ -301,6 +301,42 @@ TEST_CASE("StringTools: binaryEscapseConversion2", "[helpers]") {
|
||||
CHECK(rstring == testString);
|
||||
}
|
||||
|
||||
TEST_CASE("StringTools: binaryEscapseConversion_withX", "[helpers]") {
|
||||
std::string testString("hippy\\x35mm\\XF3_helpX26fox19");
|
||||
testString.push_back(0);
|
||||
testString.push_back(0);
|
||||
testString.push_back(0);
|
||||
testString.push_back(56);
|
||||
testString.push_back(-112);
|
||||
testString.push_back(-112);
|
||||
testString.push_back(39);
|
||||
testString.push_back(97);
|
||||
std::string estring = CLI::detail::binary_escape_string(testString);
|
||||
CHECK(CLI::detail::is_binary_escaped_string(estring));
|
||||
std::string rstring = CLI::detail::extract_binary_string(estring);
|
||||
CHECK(rstring == testString);
|
||||
}
|
||||
|
||||
TEST_CASE("StringTools: binaryEscapseConversion_withBrackets", "[helpers]") {
|
||||
|
||||
std::string vstr = R"raw('B"([\xb0\x0a\xb0/\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0])"')raw";
|
||||
std::string testString("[");
|
||||
testString.push_back(-80);
|
||||
testString.push_back('\n');
|
||||
testString.push_back(-80);
|
||||
testString.push_back('/');
|
||||
for(int ii = 0; ii < 13; ++ii) {
|
||||
testString.push_back(-80);
|
||||
}
|
||||
testString.push_back(']');
|
||||
|
||||
std::string estring = CLI::detail::binary_escape_string(testString);
|
||||
CHECK(CLI::detail::is_binary_escaped_string(estring));
|
||||
CHECK(estring == vstr);
|
||||
std::string rstring = CLI::detail::extract_binary_string(estring);
|
||||
CHECK(rstring == testString);
|
||||
}
|
||||
|
||||
TEST_CASE("StringTools: binaryStrings", "[helpers]") {
|
||||
std::string rstring = "B\"()\"";
|
||||
CHECK(CLI::detail::extract_binary_string(rstring).empty());
|
||||
|
BIN
tests/fuzzFail/round_trip_custom1
Normal file
BIN
tests/fuzzFail/round_trip_custom1
Normal file
Binary file not shown.
1
tests/fuzzFail/round_trip_custom2
Normal file
1
tests/fuzzFail/round_trip_custom2
Normal file
@ -0,0 +1 @@
|
||||
--vM=[ー
ー/ーーーーーーーーーーーーー]
|
Loading…
x
Reference in New Issue
Block a user