From 16aa7cff8d33394e19b044c9d54e37dcc16cdb22 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sat, 17 May 2025 13:30:44 -0700 Subject: [PATCH 01/51] add fuzz_fail file --- .../cli11_app_roundtrip_fail_artifact.txt | Bin 0 -> 135 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt diff --git a/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt b/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt new file mode 100644 index 0000000000000000000000000000000000000000..66a633c5ce923b7e44376f5aea65441a2201083d GIT binary patch literal 135 YcmdPZEpxF=;L_1?7${IsVwAuD0OL_1$^ZZW literal 0 HcmV?d00001 From 8b90a5454373f837b371c595e8d3f46a8c333734 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sat, 17 May 2025 14:20:29 -0700 Subject: [PATCH 02/51] fix the fuzz fail --- include/CLI/impl/Config_inl.hpp | 11 ++++++++++- tests/FuzzFailTest.cpp | 2 +- ...undtrip_fail_artifact.txt => round_trip_custom5} | Bin 3 files changed, 11 insertions(+), 2 deletions(-) rename tests/fuzzFail/{cli11_app_roundtrip_fail_artifact.txt => round_trip_custom5} (100%) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index c1592b82b..554e6dade 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -84,7 +84,16 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, } if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { - return std::string(multiline_literal_quote) + arg + multiline_literal_quote; + if (arg.front() == '\n') + { + //glitch if first character is new line it will be ignored + return std::string(multiline_literal_quote) + '\n'+arg + multiline_literal_quote; + } + else + { + return std::string(multiline_literal_quote) + arg + multiline_literal_quote; + } + } return std::string(1, stringQuote) + detail::add_escaped_characters(arg) + stringQuote; } diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index e03e2aea6..9abf436b7 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -312,7 +312,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(1, 5)); + int index = GENERATE(range(1, 6)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); diff --git a/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt b/tests/fuzzFail/round_trip_custom5 similarity index 100% rename from tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt rename to tests/fuzzFail/round_trip_custom5 From 444f4154b03c386be31100825ea262fbf741b176 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sat, 17 May 2025 14:36:20 -0700 Subject: [PATCH 03/51] add fuzz_fail file --- tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt diff --git a/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt b/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt new file mode 100644 index 000000000..5dd3c7ee7 --- /dev/null +++ b/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt @@ -0,0 +1,2 @@ +--vD=`\\\\\\\\\\\\\\\\\\\ +--vA\\\\\\\\\\\\\\\\\\\@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\\\\\\\\\\\\\\\\\\\\\\\\\\\=0\\\\\\\\ \ No newline at end of file From e1e337e1753fc8ccbe0846981113fac0c87cfd76 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 00:01:53 +0000 Subject: [PATCH 04/51] style: pre-commit.ci fixes --- include/CLI/impl/Config_inl.hpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 554e6dade..61e55030b 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -84,16 +84,12 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, } if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { - if (arg.front() == '\n') - { - //glitch if first character is new line it will be ignored - return std::string(multiline_literal_quote) + '\n'+arg + multiline_literal_quote; - } - else - { + if(arg.front() == '\n') { + // glitch if first character is new line it will be ignored + return std::string(multiline_literal_quote) + '\n' + arg + multiline_literal_quote; + } else { return std::string(multiline_literal_quote) + arg + multiline_literal_quote; } - } return std::string(1, stringQuote) + detail::add_escaped_characters(arg) + stringQuote; } From 9389b30904062ae800ac95e0d7c0fa360fe6e6d2 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sat, 17 May 2025 17:02:46 -0700 Subject: [PATCH 05/51] add fuzz_fail file --- .../cli11_app_roundtrip_fail_artifact.txt | 111 +++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt b/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt index 5dd3c7ee7..25eb231a6 100644 --- a/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt +++ b/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt @@ -1,2 +1,109 @@ ---vD=`\\\\\\\\\\\\\\\\\\\ ---vA\\\\\\\\\\\\\\\\\\\@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\\\\\\\\\\\\\\\\\\\\\\\\\\\=0\\\\\\\\ \ No newline at end of file +--vD=` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +5=,, +pt \ No newline at end of file From c567983045befc64fa6a051d3908a16d42b02355 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sat, 17 May 2025 17:05:01 -0700 Subject: [PATCH 06/51] move fuzzer fail --- tests/FuzzFailTest.cpp | 2 +- ...cli11_app_roundtrip_fail_artifact.txt => round_trip_custom6} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/fuzzFail/{cli11_app_roundtrip_fail_artifact.txt => round_trip_custom6} (100%) diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 9abf436b7..3207b23b3 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -312,7 +312,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(1, 6)); + int index = GENERATE(range(1, 7)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); diff --git a/tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt b/tests/fuzzFail/round_trip_custom6 similarity index 100% rename from tests/fuzzFail/cli11_app_roundtrip_fail_artifact.txt rename to tests/fuzzFail/round_trip_custom6 From 1ff0174a77ceff2d8a8ceb7be3a60c264d9e354b Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sat, 17 May 2025 17:34:52 -0700 Subject: [PATCH 07/51] handle carriage return properly --- include/CLI/impl/Config_inl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 61e55030b..83be52ed6 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -84,8 +84,8 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, } if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { - if(arg.front() == '\n') { - // glitch if first character is new line it will be ignored + if(arg.front() == '\n'||arg.front()=='\r') { + // glitch if first character is new line it will be ignored so add extra new line return std::string(multiline_literal_quote) + '\n' + arg + multiline_literal_quote; } else { return std::string(multiline_literal_quote) + arg + multiline_literal_quote; From 90acdbbb7e6f0dbb9632d6c9bada0bbf37d4ab63 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 00:35:57 +0000 Subject: [PATCH 08/51] style: pre-commit.ci fixes --- include/CLI/impl/Config_inl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 83be52ed6..635ab6e7f 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -84,7 +84,7 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, } if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { - if(arg.front() == '\n'||arg.front()=='\r') { + if(arg.front() == '\n' || arg.front() == '\r') { // glitch if first character is new line it will be ignored so add extra new line return std::string(multiline_literal_quote) + '\n' + arg + multiline_literal_quote; } else { From 7bb012fe881d05011ec2ca0b82271c8ee6de5f61 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sat, 17 May 2025 17:48:44 -0700 Subject: [PATCH 09/51] try to add more debug output to the tests --- tests/FuzzFailTest.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 3207b23b3..5e8fc0312 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -332,6 +332,11 @@ TEST_CASE("app_roundtrip_custom") { } app2->parse_from_stream(out); auto result = fuzzdata2.compare(fuzzdata); + if (!result) + { + std::cout< Date: Sun, 18 May 2025 00:49:24 +0000 Subject: [PATCH 10/51] style: pre-commit.ci fixes --- tests/FuzzFailTest.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 5e8fc0312..5137f7e7b 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -332,10 +332,9 @@ TEST_CASE("app_roundtrip_custom") { } app2->parse_from_stream(out); auto result = fuzzdata2.compare(fuzzdata); - if (!result) - { - std::cout< Date: Sat, 17 May 2025 18:54:08 -0700 Subject: [PATCH 11/51] try to catch a few other carriage returns --- include/CLI/impl/Config_inl.hpp | 2 +- include/CLI/impl/StringTools_inl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 635ab6e7f..38b5dbab9 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -28,7 +28,7 @@ namespace detail { CLI11_INLINE bool is_printable(const std::string &test_string) { return std::all_of(test_string.begin(), test_string.end(), [](char x) { - return (isprint(static_cast(x)) != 0 || x == '\n' || x == '\t'); + return (isprint(static_cast(x)) != 0 || x == '\n' || x == '\r'|| x == '\t'); }); } diff --git a/include/CLI/impl/StringTools_inl.hpp b/include/CLI/impl/StringTools_inl.hpp index 72736daaf..c467342b7 100644 --- a/include/CLI/impl/StringTools_inl.hpp +++ b/include/CLI/impl/StringTools_inl.hpp @@ -86,7 +86,7 @@ CLI11_INLINE std::string &remove_outer(std::string &str, char key) { CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) { std::string::size_type n = 0; while(n != std::string::npos && n < input.size()) { - n = input.find('\n', n); + n = input.find_first_of("\r\n", n); if(n != std::string::npos) { input = input.substr(0, n + 1) + leader + input.substr(n + 1); n += leader.size(); From f6fb11a0490527db42f8f12e43d997614551278a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 01:56:25 +0000 Subject: [PATCH 12/51] style: pre-commit.ci fixes --- include/CLI/impl/Config_inl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 38b5dbab9..a19798347 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -28,7 +28,7 @@ namespace detail { CLI11_INLINE bool is_printable(const std::string &test_string) { return std::all_of(test_string.begin(), test_string.end(), [](char x) { - return (isprint(static_cast(x)) != 0 || x == '\n' || x == '\r'|| x == '\t'); + return (isprint(static_cast(x)) != 0 || x == '\n' || x == '\r' || x == '\t'); }); } From e87e040592367b001b692fcb8a0f9b1bbbc14bb3 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 05:15:06 -0700 Subject: [PATCH 13/51] add debugging output --- fuzz/fuzzApp.cpp | 31 ++++++++++++++++++++++++++++++- fuzz/fuzzApp.hpp | 2 +- tests/FuzzFailTest.cpp | 4 ++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 9d050eae4..18e711605 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -6,6 +6,7 @@ #include "fuzzApp.hpp" #include +#include namespace CLI { /* @@ -151,7 +152,7 @@ std::shared_ptr FuzzApp::generateApp() { return fApp; } -bool FuzzApp::compare(const FuzzApp &other) const { +bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { if(val32 != other.val32) { return false; } @@ -291,6 +292,34 @@ bool FuzzApp::compare(const FuzzApp &other) const { std::vector 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()="< #include +#include std::string loadFailureFile(const std::string &type, int index) { std::string fileName(TEST_FILE_FOLDER "/fuzzFail/"); @@ -333,8 +334,7 @@ TEST_CASE("app_roundtrip_custom") { app2->parse_from_stream(out); auto result = fuzzdata2.compare(fuzzdata); if(!result) { - std::cout << parseData << "parsed\n"; - std::cout << '\n' << configOut << '\n'; + result=fuzzdata2.compare(fuzzdata,true); } CHECK(result); } From b716cdc82e009b6f52ab69592873bb9a2e0b64b4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 12:15:50 +0000 Subject: [PATCH 14/51] style: pre-commit.ci fixes --- fuzz/fuzzApp.cpp | 41 ++++++++++++++++++----------------------- fuzz/fuzzApp.hpp | 2 +- tests/FuzzFailTest.cpp | 4 ++-- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 18e711605..a62349895 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -292,33 +292,28 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { std::vector 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()="< #include #include -#include std::string loadFailureFile(const std::string &type, int index) { std::string fileName(TEST_FILE_FOLDER "/fuzzFail/"); @@ -334,7 +334,7 @@ TEST_CASE("app_roundtrip_custom") { app2->parse_from_stream(out); auto result = fuzzdata2.compare(fuzzdata); if(!result) { - result=fuzzdata2.compare(fuzzdata,true); + result = fuzzdata2.compare(fuzzdata, true); } CHECK(result); } From 3eed508d3ee587c90754c6f331c08908a767ed64 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 05:29:18 -0700 Subject: [PATCH 15/51] tune the debugging output --- fuzz/fuzzApp.cpp | 2 +- include/CLI/impl/Config_inl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index a62349895..45f685672 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -306,7 +306,7 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { std::cout << "string[" << ii << "]:vstrD[" << jj << "]=" << static_cast(res[ii][jj]) << ", other.vstrD[" << jj << "]=[empty] \n"; - } else { + } else if (res[ii][jj]!=other.vstrD[ii][jj]){ std::cout << "string[" << ii << "]:vstrD[" << jj << "]=" << static_cast(res[ii][jj]) << ", other.vstrD[" << jj << "]=" << static_cast(other.vstrD[ii][jj]) << '\n'; diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index a19798347..635ab6e7f 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -28,7 +28,7 @@ namespace detail { CLI11_INLINE bool is_printable(const std::string &test_string) { return std::all_of(test_string.begin(), test_string.end(), [](char x) { - return (isprint(static_cast(x)) != 0 || x == '\n' || x == '\r' || x == '\t'); + return (isprint(static_cast(x)) != 0 || x == '\n' || x == '\t'); }); } From 38301ac672a04bc148c68c76be7fb9992b2fad65 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 12:29:38 +0000 Subject: [PATCH 16/51] style: pre-commit.ci fixes --- fuzz/fuzzApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 45f685672..9ea04ef24 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -306,7 +306,7 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { std::cout << "string[" << ii << "]:vstrD[" << jj << "]=" << static_cast(res[ii][jj]) << ", other.vstrD[" << jj << "]=[empty] \n"; - } else if (res[ii][jj]!=other.vstrD[ii][jj]){ + } else if(res[ii][jj] != other.vstrD[ii][jj]) { std::cout << "string[" << ii << "]:vstrD[" << jj << "]=" << static_cast(res[ii][jj]) << ", other.vstrD[" << jj << "]=" << static_cast(other.vstrD[ii][jj]) << '\n'; From 2775a90ec10dd3b79f8ec82bd83a3ec4f3c2454c Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 06:52:39 -0700 Subject: [PATCH 17/51] more debugging --- tests/FuzzFailTest.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index b5c9bec27..108ba7b61 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -6,9 +6,9 @@ #include "../fuzz/fuzzApp.hpp" #include "app_helper.hpp" -#include #include #include +#include std::string loadFailureFile(const std::string &type, int index) { std::string fileName(TEST_FILE_FOLDER "/fuzzFail/"); @@ -335,6 +335,8 @@ TEST_CASE("app_roundtrip_custom") { auto result = fuzzdata2.compare(fuzzdata); if(!result) { result = fuzzdata2.compare(fuzzdata, true); + std::cout << "\n:parsed:\n"<< parseData; + std::cout << "\n:config:\n" << configOut << '\n'; } CHECK(result); } From 3dcc9a9730ed5de3db57a47d93a22e007596a136 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 13:52:58 +0000 Subject: [PATCH 18/51] style: pre-commit.ci fixes --- tests/FuzzFailTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 108ba7b61..807861cd1 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -6,9 +6,9 @@ #include "../fuzz/fuzzApp.hpp" #include "app_helper.hpp" +#include #include #include -#include std::string loadFailureFile(const std::string &type, int index) { std::string fileName(TEST_FILE_FOLDER "/fuzzFail/"); @@ -335,7 +335,7 @@ TEST_CASE("app_roundtrip_custom") { auto result = fuzzdata2.compare(fuzzdata); if(!result) { result = fuzzdata2.compare(fuzzdata, true); - std::cout << "\n:parsed:\n"<< parseData; + std::cout << "\n:parsed:\n" << parseData; std::cout << "\n:config:\n" << configOut << '\n'; } CHECK(result); From 3d0fb85459383a0fe70d47454d35ffd3d69f550c Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 07:39:33 -0700 Subject: [PATCH 19/51] add more debugging output --- fuzz/fuzzApp.cpp | 5 ++++- include/CLI/impl/Config_inl.hpp | 2 +- tests/FuzzFailTest.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 9ea04ef24..69147904b 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -307,9 +307,12 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { << "]=" << static_cast(res[ii][jj]) << ", other.vstrD[" << jj << "]=[empty] \n"; } else if(res[ii][jj] != other.vstrD[ii][jj]) { - std::cout << "string[" << ii << "]:vstrD[" << jj + std::cout << "-->string[" << ii << "]:vstrD[" << jj << "]=" << static_cast(res[ii][jj]) << ", other.vstrD[" << jj << "]=" << static_cast(other.vstrD[ii][jj]) << '\n'; + } else { + std::cout << "string[" << ii << "]:vstrD[" << jj + << "]=" << static_cast(res[ii][jj]) << '\n'; } } } diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 635ab6e7f..99b7dc2ef 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -398,7 +398,7 @@ inline std::vector ConfigBase::from_config(std::istream &input) cons } lineExtension = false; firstLine = false; - if(!l2.empty() && l2.back() == '\\') { + if(!l2.empty() && l2.back() == '\\'&& keyChar == '\"') { lineExtension = true; l2.pop_back(); } diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 807861cd1..472722195 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -334,7 +334,7 @@ TEST_CASE("app_roundtrip_custom") { app2->parse_from_stream(out); auto result = fuzzdata2.compare(fuzzdata); if(!result) { - result = fuzzdata2.compare(fuzzdata, true); + result = fuzzdata.compare(fuzzdata2, true); std::cout << "\n:parsed:\n" << parseData; std::cout << "\n:config:\n" << configOut << '\n'; } From 8464c0d4bd5c92031b39a0c80d2226b74ba6b66f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 14:39:52 +0000 Subject: [PATCH 20/51] style: pre-commit.ci fixes --- fuzz/fuzzApp.cpp | 2 +- include/CLI/impl/Config_inl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 69147904b..a086c8ddf 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -312,7 +312,7 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { << "]=" << static_cast(other.vstrD[ii][jj]) << '\n'; } else { std::cout << "string[" << ii << "]:vstrD[" << jj - << "]=" << static_cast(res[ii][jj]) << '\n'; + << "]=" << static_cast(res[ii][jj]) << '\n'; } } } diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 99b7dc2ef..58f178fe9 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -398,7 +398,7 @@ inline std::vector ConfigBase::from_config(std::istream &input) cons } lineExtension = false; firstLine = false; - if(!l2.empty() && l2.back() == '\\'&& keyChar == '\"') { + if(!l2.empty() && l2.back() == '\\' && keyChar == '\"') { lineExtension = true; l2.pop_back(); } From 0e9fedde2a5c5b072eedd05d0e5b4c4fff33e0d8 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 12:06:52 -0700 Subject: [PATCH 21/51] add fuzz_fail file7 --- tests/fuzzFail/round_trip_custom7 | 106 ++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 tests/fuzzFail/round_trip_custom7 diff --git a/tests/fuzzFail/round_trip_custom7 b/tests/fuzzFail/round_trip_custom7 new file mode 100644 index 000000000..e6e535cce --- /dev/null +++ b/tests/fuzzFail/round_trip_custom7 @@ -0,0 +1,106 @@ +--vD=` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +5=,, +pt \ No newline at end of file From 3eb8dee89cf902f5137846e3edb741419d4910b0 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 12:13:20 -0700 Subject: [PATCH 22/51] try adding a fuzz fail test --- tests/FuzzFailTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 472722195..c6ebca1c9 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -313,7 +313,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(1, 7)); + int index = GENERATE(range(7, 8)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); From d2e276cd5d55f8deed9a2c4c1dac17ed9ba28858 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 12:23:03 -0700 Subject: [PATCH 23/51] fix clang tidy issue --- include/CLI/impl/Config_inl.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 58f178fe9..4c888d257 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -84,12 +84,14 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, } if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { - if(arg.front() == '\n' || arg.front() == '\r') { - // glitch if first character is new line it will be ignored so add extra new line - return std::string(multiline_literal_quote) + '\n' + arg + multiline_literal_quote; - } else { - return std::string(multiline_literal_quote) + arg + multiline_literal_quote; + std::string return_string{multiline_literal_quote}; + return_string.reserve(7+arg.size()); + if (arg.front() == '\n' || arg.front() == '\r') { + return_string.push_back('\n'); } + return_string.append(arg); + return_string.append(multiline_literal_quote,3); + return return_string; } return std::string(1, stringQuote) + detail::add_escaped_characters(arg) + stringQuote; } From 49cd53439dbbc572135c27f43995596229f90357 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 19:23:21 +0000 Subject: [PATCH 24/51] style: pre-commit.ci fixes --- include/CLI/impl/Config_inl.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 4c888d257..e16db3285 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -85,12 +85,12 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { std::string return_string{multiline_literal_quote}; - return_string.reserve(7+arg.size()); - if (arg.front() == '\n' || arg.front() == '\r') { + return_string.reserve(7 + arg.size()); + if(arg.front() == '\n' || arg.front() == '\r') { return_string.push_back('\n'); } return_string.append(arg); - return_string.append(multiline_literal_quote,3); + return_string.append(multiline_literal_quote, 3); return return_string; } return std::string(1, stringQuote) + detail::add_escaped_characters(arg) + stringQuote; From 300816ef80722a41d1fcc5be230a1d44042881da Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 12:56:44 -0700 Subject: [PATCH 25/51] try another tweak --- include/CLI/impl/Config_inl.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index e16db3285..7376679e2 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -84,6 +84,10 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, } if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { + if (arg.find(multiline_literal_quote) != std::string::npos) + { + return binary_escape_string(arg); + } std::string return_string{multiline_literal_quote}; return_string.reserve(7 + arg.size()); if(arg.front() == '\n' || arg.front() == '\r') { From d47f501610a2911a201913e7bbb14a25aa181269 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 19:57:37 +0000 Subject: [PATCH 26/51] style: pre-commit.ci fixes --- include/CLI/impl/Config_inl.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 7376679e2..8e96ddc49 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -84,8 +84,7 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, } if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { - if (arg.find(multiline_literal_quote) != std::string::npos) - { + if(arg.find(multiline_literal_quote) != std::string::npos) { return binary_escape_string(arg); } std::string return_string{multiline_literal_quote}; From a90b5fb5ab4dcfc9b1fd38948264c185c5a0e84b Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 14:11:09 -0700 Subject: [PATCH 27/51] add fuzz_fail file8 --- tests/fuzzFail/round_trip_custom8 | Bin 0 -> 77 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fuzzFail/round_trip_custom8 diff --git a/tests/fuzzFail/round_trip_custom8 b/tests/fuzzFail/round_trip_custom8 new file mode 100644 index 0000000000000000000000000000000000000000..54f17d9a7cf41ed84793d7df0b523eadd2b04d47 GIT binary patch literal 77 zcmcCX%SlYnx5>B3%}>cp%S Date: Sun, 18 May 2025 15:34:58 -0700 Subject: [PATCH 28/51] handle custom options better for configurable modifier --- fuzz/fuzzApp.cpp | 37 +++++++++++++++++++++++++++---------- fuzz/fuzzApp.hpp | 4 ++-- tests/FuzzFailTest.cpp | 2 +- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index a086c8ddf..3051a2bd0 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -338,8 +338,10 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) 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) { + return false; + } } } // now test custom vector_options @@ -347,8 +349,10 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { 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; @@ -474,11 +478,15 @@ 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()); - auto *opt = app->add_option(name, *(custom_string_options.back())); + custom_string_options.push_back(std::make_shared>("",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; + } } current_index = end_option + 9; @@ -492,12 +500,16 @@ 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()); - auto *opt = app->add_option(name, *(custom_string_options.back())); + custom_string_options.push_back(std::make_shared>("",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; + } } current_index = end_option + 7; } else if(description_string.compare(current_index, 7, ">()); - auto *opt = app->add_option(name, *(custom_vector_options.back())); + custom_vector_options.push_back(std::make_shared,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; + } } current_index = end_option + 9; } else { diff --git a/fuzz/fuzzApp.hpp b/fuzz/fuzzApp.hpp index 22a6181a0..96d67c584 100644 --- a/fuzz/fuzzApp.hpp +++ b/fuzz/fuzzApp.hpp @@ -121,7 +121,7 @@ class FuzzApp { std::vector vstrF{}; std::string mergeBuffer{}; std::vector validator_strings{}; - std::vector> custom_string_options{}; - std::vector>> custom_vector_options{}; + std::vector>> custom_string_options{}; + std::vector,bool>>> custom_vector_options{}; }; } // namespace CLI diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index c6ebca1c9..adf7255d6 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -313,7 +313,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(7, 8)); + int index = GENERATE(range(1, 9)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); From eb4ca0ca7b8650ad2ae990254ffd7d95d3c66f2d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 22:35:18 +0000 Subject: [PATCH 29/51] style: pre-commit.ci fixes --- fuzz/fuzzApp.cpp | 27 ++++++++++++--------------- fuzz/fuzzApp.hpp | 4 ++-- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 3051a2bd0..a52edd14b 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -339,7 +339,7 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { } for(std::size_t ii = 0; ii < custom_string_options.size(); ++ii) { if(custom_string_options[ii]->first != other.custom_string_options[ii]->first) { - if (custom_string_options[ii]->second) { + if(custom_string_options[ii]->second) { return false; } } @@ -350,7 +350,7 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { } for(std::size_t ii = 0; ii < custom_vector_options.size(); ++ii) { if(custom_vector_options[ii]->first != other.custom_vector_options[ii]->first) { - if (custom_vector_options[ii]->second) { + if(custom_vector_options[ii]->second) { return false; } } @@ -478,14 +478,13 @@ 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>("",true)); + custom_string_options.push_back(std::make_shared>("", 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_configurable()) { + custom_string_options.back()->second = false; } } @@ -500,15 +499,14 @@ 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>("",true)); + custom_string_options.push_back(std::make_shared>("", 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_configurable()) { + custom_string_options.back()->second = false; } } current_index = end_option + 7; @@ -522,15 +520,14 @@ 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,bool>>()); - custom_vector_options.back()->second=true; + custom_vector_options.push_back(std::make_shared, 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_configurable()) { + custom_vector_options.back()->second = false; } } current_index = end_option + 9; diff --git a/fuzz/fuzzApp.hpp b/fuzz/fuzzApp.hpp index 96d67c584..2e6e0aaf6 100644 --- a/fuzz/fuzzApp.hpp +++ b/fuzz/fuzzApp.hpp @@ -121,7 +121,7 @@ class FuzzApp { std::vector vstrF{}; std::string mergeBuffer{}; std::vector validator_strings{}; - std::vector>> custom_string_options{}; - std::vector,bool>>> custom_vector_options{}; + std::vector>> custom_string_options{}; + std::vector, bool>>> custom_vector_options{}; }; } // namespace CLI From 82d20d76d48d44db2c5f72f06b17aad161218108 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 15:59:36 -0700 Subject: [PATCH 30/51] add fuzz_fail file9 --- tests/fuzzFail/round_trip_custom9 | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/fuzzFail/round_trip_custom9 diff --git a/tests/fuzzFail/round_trip_custom9 b/tests/fuzzFail/round_trip_custom9 new file mode 100644 index 000000000..724642f40 --- /dev/null +++ b/tests/fuzzFail/round_trip_custom9 @@ -0,0 +1 @@ +--flag=-Adlag=-AB-v,ag=-ABB-A-v""""""""""""""""""""""""""""""""""""""""""''''''''''''''''''''''''''''''''''''""""""""""""""",ag=-AB-"x \ No newline at end of file From ca31efab910de7a19438f1e67b3313aec68ee17c Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 16:29:20 -0700 Subject: [PATCH 31/51] string control for binary strings --- include/CLI/StringTools.hpp | 2 +- include/CLI/impl/Config_inl.hpp | 2 +- include/CLI/impl/StringTools_inl.hpp | 4 ++-- tests/FuzzFailTest.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/CLI/StringTools.hpp b/include/CLI/StringTools.hpp index e17e11a21..520ac2cbf 100644 --- a/include/CLI/StringTools.hpp +++ b/include/CLI/StringTools.hpp @@ -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); diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 8e96ddc49..f4965c21c 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -85,7 +85,7 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { if(arg.find(multiline_literal_quote) != std::string::npos) { - return binary_escape_string(arg); + return binary_escape_string(arg,true); } std::string return_string{multiline_literal_quote}; return_string.reserve(7 + arg.size()); diff --git a/include/CLI/impl/StringTools_inl.hpp b/include/CLI/impl/StringTools_inl.hpp index c467342b7..e6e9c5338 100644 --- a/include/CLI/impl/StringTools_inl.hpp +++ b/include/CLI/impl/StringTools_inl.hpp @@ -422,7 +422,7 @@ CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) { return offset + 1; } -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) { // s is our escaped output string std::string escaped_string{}; // loop through all characters @@ -449,7 +449,7 @@ CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escap escaped_string.push_back(c); } } - if(escaped_string != string_to_escape) { + if(escaped_string != string_to_escape || force) { auto sqLoc = escaped_string.find('\''); while(sqLoc != std::string::npos) { escaped_string[sqLoc] = '\\'; diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index adf7255d6..53c04493f 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -313,7 +313,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(1, 9)); + int index = GENERATE(range(1, 10)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); From e2f0b8bff5d9c3ec79ad7a07066b676eac9dda6b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 23:29:44 +0000 Subject: [PATCH 32/51] style: pre-commit.ci fixes --- include/CLI/StringTools.hpp | 2 +- include/CLI/impl/Config_inl.hpp | 2 +- include/CLI/impl/StringTools_inl.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/CLI/StringTools.hpp b/include/CLI/StringTools.hpp index 520ac2cbf..aaba68d3d 100644 --- a/include/CLI/StringTools.hpp +++ b/include/CLI/StringTools.hpp @@ -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, bool force=false); +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); diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index f4965c21c..abaf57c0d 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -85,7 +85,7 @@ convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, if(detail::has_escapable_character(arg)) { if(arg.size() > 100 && !disable_multi_line) { if(arg.find(multiline_literal_quote) != std::string::npos) { - return binary_escape_string(arg,true); + return binary_escape_string(arg, true); } std::string return_string{multiline_literal_quote}; return_string.reserve(7 + arg.size()); diff --git a/include/CLI/impl/StringTools_inl.hpp b/include/CLI/impl/StringTools_inl.hpp index e6e9c5338..a67daf59c 100644 --- a/include/CLI/impl/StringTools_inl.hpp +++ b/include/CLI/impl/StringTools_inl.hpp @@ -422,7 +422,7 @@ CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) { return offset + 1; } -CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape,bool force) { +CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force) { // s is our escaped output string std::string escaped_string{}; // loop through all characters From 43856cc65327423ec603aba481f52e310ee24cc4 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 17:07:15 -0700 Subject: [PATCH 33/51] add check for invalid configurations --- fuzz/fuzzApp.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index a52edd14b..18cd34d91 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -485,6 +485,11 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_string_options.back()->second = false; + if (!opt->get_required()) + { + //this will always cause a failure so don't allow it + throw(CLI::InvalidError("required and non configurable not allowed together")); + } } } @@ -507,6 +512,11 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_string_options.back()->second = false; + if (!opt->get_required()) + { + //this will always cause a failure so don't allow it + throw(CLI::InvalidError("required and non configurable not allowed together")); + } } } current_index = end_option + 7; @@ -528,6 +538,11 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_vector_options.back()->second = false; + if (!opt->get_required()) + { + //this will always cause a failure so don't allow it + throw(CLI::InvalidError("required and non configurable not allowed together")); + } } } current_index = end_option + 9; From 2964902161eaeee248424f160b0259a1ad11f3f4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 00:07:34 +0000 Subject: [PATCH 34/51] style: pre-commit.ci fixes --- fuzz/fuzzApp.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 18cd34d91..959107a6f 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -485,9 +485,8 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_string_options.back()->second = false; - if (!opt->get_required()) - { - //this will always cause a failure so don't allow it + if(!opt->get_required()) { + // this will always cause a failure so don't allow it throw(CLI::InvalidError("required and non configurable not allowed together")); } } @@ -512,9 +511,8 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_string_options.back()->second = false; - if (!opt->get_required()) - { - //this will always cause a failure so don't allow it + if(!opt->get_required()) { + // this will always cause a failure so don't allow it throw(CLI::InvalidError("required and non configurable not allowed together")); } } @@ -538,9 +536,8 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_vector_options.back()->second = false; - if (!opt->get_required()) - { - //this will always cause a failure so don't allow it + if(!opt->get_required()) { + // this will always cause a failure so don't allow it throw(CLI::InvalidError("required and non configurable not allowed together")); } } From 07005f9ebb3ae4227fc1f17fcafee08feb319e8b Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 17:44:44 -0700 Subject: [PATCH 35/51] use incorrect construction instead of invalid error --- fuzz/fuzzApp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 959107a6f..8bfa51f92 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -487,7 +487,7 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri custom_string_options.back()->second = false; if(!opt->get_required()) { // this will always cause a failure so don't allow it - throw(CLI::InvalidError("required and non configurable not allowed together")); + throw(CLI::IncorrectConstruction("required and non configurable not allowed together")); } } } @@ -513,7 +513,7 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri custom_string_options.back()->second = false; if(!opt->get_required()) { // this will always cause a failure so don't allow it - throw(CLI::InvalidError("required and non configurable not allowed together")); + throw(CLI::IncorrectConstruction("required and non configurable not allowed together")); } } } @@ -538,7 +538,7 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri custom_vector_options.back()->second = false; if(!opt->get_required()) { // this will always cause a failure so don't allow it - throw(CLI::InvalidError("required and non configurable not allowed together")); + throw(CLI::IncorrectConstruction("required and non configurable not allowed together")); } } } From 35cd209b770b5b13fb51179684895f941c28d39d Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 19:00:59 -0700 Subject: [PATCH 36/51] add fuzz_fail file9 --- tests/fuzzFail/round_trip_custom10 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/fuzzFail/round_trip_custom10 diff --git a/tests/fuzzFail/round_trip_custom10 b/tests/fuzzFail/round_trip_custom10 new file mode 100644 index 000000000..5b397bb46 --- /dev/null +++ b/tests/fuzzFail/round_trip_custom10 @@ -0,0 +1,7 @@ +a-'o-aOoptggggggggggggggggggggggg'o-aOopt4 h- +Ev +-.v'flagtup̐oop2flag<tttfapt2 \ No newline at end of file From 59713f35bf74e88a1b6b314c3dca916a259912fa Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 19:25:06 -0700 Subject: [PATCH 37/51] rework the fuzzing tests a bit --- fuzz/cli11_app_fuzz.cpp | 30 +++++++++++++++++------------- fuzz/fuzzApp.cpp | 15 ++++++--------- fuzz/fuzzApp.hpp | 5 ++++- tests/FuzzFailTest.cpp | 34 ++++++++++++++++++---------------- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/fuzz/cli11_app_fuzz.cpp b/fuzz/cli11_app_fuzz.cpp index a5e518f48..7de3b7c77 100644 --- a/fuzz/cli11_app_fuzz.cpp +++ b/fuzz/cli11_app_fuzz.cpp @@ -17,9 +17,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { std::string parseString(reinterpret_cast(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); @@ -40,17 +39,22 @@ 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; } diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 8bfa51f92..a5e97c52f 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -485,9 +485,8 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_string_options.back()->second = false; - if(!opt->get_required()) { - // this will always cause a failure so don't allow it - throw(CLI::IncorrectConstruction("required and non configurable not allowed together")); + if(opt->get_required()) { + non_config_required=true; } } } @@ -511,9 +510,8 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_string_options.back()->second = false; - if(!opt->get_required()) { - // this will always cause a failure so don't allow it - throw(CLI::IncorrectConstruction("required and non configurable not allowed together")); + if(opt->get_required()) { + non_config_required=true; } } } @@ -536,9 +534,8 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri modify_option(opt, attributes); if(!opt->get_configurable()) { custom_vector_options.back()->second = false; - if(!opt->get_required()) { - // this will always cause a failure so don't allow it - throw(CLI::IncorrectConstruction("required and non configurable not allowed together")); + if(opt->get_required()) { + non_config_required=true; } } } diff --git a/fuzz/fuzzApp.hpp b/fuzz/fuzzApp.hpp index 2e6e0aaf6..f8131bea3 100644 --- a/fuzz/fuzzApp.hpp +++ b/fuzz/fuzzApp.hpp @@ -61,8 +61,9 @@ class FuzzApp { /** 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); + bool support_config_file_only() const{return !non_config_required;} int32_t val32{0}; int16_t val16{0}; int8_t val8{0}; @@ -123,5 +124,7 @@ class FuzzApp { std::vector validator_strings{}; std::vector>> custom_string_options{}; std::vector, bool>>> custom_vector_options{}; +private: + bool non_config_required{false}; }; } // namespace CLI diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 53c04493f..0ef6d4b9d 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -313,7 +313,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(1, 10)); + int index = GENERATE(range(10, 11)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); @@ -323,22 +323,24 @@ TEST_CASE("app_roundtrip_custom") { } 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); - if(!result) { - result = fuzzdata.compare(fuzzdata2, true); - std::cout << "\n:parsed:\n" << parseData; - std::cout << "\n:config:\n" << configOut << '\n'; + if (fuzzdata.support_config_file_only()) + { + // 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); + if (!result) { + result = fuzzdata.compare(fuzzdata2, true); + std::cout << "\n:parsed:\n" << parseData; + std::cout << "\n:config:\n" << configOut << '\n'; + } + CHECK(result); } - CHECK(result); } // this test From cd2425b13d528c0b92f1ff32c26158032bae5c15 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 02:25:28 +0000 Subject: [PATCH 38/51] style: pre-commit.ci fixes --- fuzz/cli11_app_fuzz.cpp | 7 +++---- fuzz/fuzzApp.cpp | 6 +++--- fuzz/fuzzApp.hpp | 5 +++-- tests/FuzzFailTest.cpp | 7 +++---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/fuzz/cli11_app_fuzz.cpp b/fuzz/cli11_app_fuzz.cpp index 7de3b7c77..d5683b6ca 100644 --- a/fuzz/cli11_app_fuzz.cpp +++ b/fuzz/cli11_app_fuzz.cpp @@ -17,7 +17,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { std::string parseString(reinterpret_cast(Data), Size); CLI::FuzzApp fuzzdata; - + auto app = fuzzdata.generateApp(); std::size_t pstring_start{0}; try { @@ -39,8 +39,7 @@ 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. } - if (fuzzdata.support_config_file_only()) - { + 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 @@ -55,6 +54,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { throw CLI::ValidationError("fuzzer", "file input results don't match parse results"); } } - + return 0; } diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index a5e97c52f..98af0eb76 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -486,7 +486,7 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri if(!opt->get_configurable()) { custom_string_options.back()->second = false; if(opt->get_required()) { - non_config_required=true; + non_config_required = true; } } } @@ -511,7 +511,7 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri if(!opt->get_configurable()) { custom_string_options.back()->second = false; if(opt->get_required()) { - non_config_required=true; + non_config_required = true; } } } @@ -535,7 +535,7 @@ std::size_t FuzzApp::add_custom_options(CLI::App *app, const std::string &descri if(!opt->get_configurable()) { custom_vector_options.back()->second = false; if(opt->get_required()) { - non_config_required=true; + non_config_required = true; } } } diff --git a/fuzz/fuzzApp.hpp b/fuzz/fuzzApp.hpp index f8131bea3..a358d455d 100644 --- a/fuzz/fuzzApp.hpp +++ b/fuzz/fuzzApp.hpp @@ -63,7 +63,7 @@ class FuzzApp { /** modify an option based on string*/ static void modify_option(CLI::Option *opt, const std::string &modifier); - bool support_config_file_only() const{return !non_config_required;} + bool support_config_file_only() const { return !non_config_required; } int32_t val32{0}; int16_t val16{0}; int8_t val8{0}; @@ -124,7 +124,8 @@ class FuzzApp { std::vector validator_strings{}; std::vector>> custom_string_options{}; std::vector, bool>>> custom_vector_options{}; -private: + + private: bool non_config_required{false}; }; } // namespace CLI diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 0ef6d4b9d..fcffa3c41 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -323,18 +323,17 @@ TEST_CASE("app_roundtrip_custom") { } else { app->parse(parseData); } - if (fuzzdata.support_config_file_only()) - { + if(fuzzdata.support_config_file_only()) { // 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) { + if(pstring_start > 0) { fuzzdata2.add_custom_options(app2.get(), parseData); } app2->parse_from_stream(out); auto result = fuzzdata2.compare(fuzzdata); - if (!result) { + if(!result) { result = fuzzdata.compare(fuzzdata2, true); std::cout << "\n:parsed:\n" << parseData; std::cout << "\n:config:\n" << configOut << '\n'; From e04b28299d4d12d6dd0ba91d66fdb3a164ab865f Mon Sep 17 00:00:00 2001 From: Philip Top Date: Sun, 18 May 2025 20:23:27 -0700 Subject: [PATCH 39/51] add fuzz_fail file11 --- tests/fuzzFail/round_trip_custom11 | Bin 0 -> 253 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fuzzFail/round_trip_custom11 diff --git a/tests/fuzzFail/round_trip_custom11 b/tests/fuzzFail/round_trip_custom11 new file mode 100644 index 0000000000000000000000000000000000000000..c7a5288321915456491629b4dbebc1281192194b GIT binary patch literal 253 zcmcCX%SlYnx5>B3%}>cp%Sp}?gU*h@6Brwkyk+5jk$Mo s@6O09FM=ooYem%qR1S1 Date: Mon, 19 May 2025 06:16:31 -0700 Subject: [PATCH 40/51] add detection for duplication positional only options that have different configuration settings --- include/CLI/impl/App_inl.hpp | 5 +++++ tests/FuzzFailTest.cpp | 15 ++++++++++----- .../{round_trip_custom11 => parse_fail_check4} | Bin 3 files changed, 15 insertions(+), 5 deletions(-) rename tests/fuzzFail/{round_trip_custom11 => parse_fail_check4} (100%) diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index 1986c15b6..fea32265b 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -178,6 +178,11 @@ CLI11_INLINE Option *App::add_option(std::string option_name, if(op != nullptr && op->get_configurable()) { throw(OptionAlreadyAdded("added option positional name matches existing option: " + test_name)); } + //need to check if there is another positional with the same name that also doesn't have any long or short names + op = get_option_no_throw(myopt.get_single_name()); + if(op != nullptr && op->lnames_.empty() && op->snames_.empty()) { + throw(OptionAlreadyAdded("unable to disambiguate with existing option: " + test_name)); + } } else if(parent_ != nullptr) { for(auto &ln : myopt.lnames_) { auto *op = parent_->get_option_no_throw(ln); diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index fcffa3c41..41a155f94 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -313,7 +313,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(10, 11)); + int index = GENERATE(range(1, 11)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); @@ -326,7 +326,6 @@ TEST_CASE("app_roundtrip_custom") { if(fuzzdata.support_config_file_only()) { // 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); @@ -348,11 +347,17 @@ TEST_CASE("app_roundtrip_parse_normal_fail") { // like HorribleErrors CLI::FuzzApp fuzzdata; auto app = fuzzdata.generateApp(); - int index = GENERATE(range(1, 4)); + int index = GENERATE(range(4, 5)); auto parseData = loadFailureFile("parse_fail_check", index); std::size_t pstring_start{0}; - pstring_start = fuzzdata.add_custom_options(app.get(), parseData); - + try { + pstring_start = fuzzdata.add_custom_options(app.get(), parseData); + } + catch (const CLI::ConstructionError&/*ce*/) + { + CHECK(true); + return; + } try { if(pstring_start > 0) { app->parse(parseData.substr(pstring_start)); diff --git a/tests/fuzzFail/round_trip_custom11 b/tests/fuzzFail/parse_fail_check4 similarity index 100% rename from tests/fuzzFail/round_trip_custom11 rename to tests/fuzzFail/parse_fail_check4 From e4e5dc6ff5b368a1829758d98d4944325c4ed177 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 13:16:53 +0000 Subject: [PATCH 41/51] style: pre-commit.ci fixes --- include/CLI/impl/App_inl.hpp | 5 +++-- tests/FuzzFailTest.cpp | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index fea32265b..97c8a52ff 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -178,9 +178,10 @@ CLI11_INLINE Option *App::add_option(std::string option_name, if(op != nullptr && op->get_configurable()) { throw(OptionAlreadyAdded("added option positional name matches existing option: " + test_name)); } - //need to check if there is another positional with the same name that also doesn't have any long or short names + // need to check if there is another positional with the same name that also doesn't have any long or short + // names op = get_option_no_throw(myopt.get_single_name()); - if(op != nullptr && op->lnames_.empty() && op->snames_.empty()) { + if(op != nullptr && op->lnames_.empty() && op->snames_.empty()) { throw(OptionAlreadyAdded("unable to disambiguate with existing option: " + test_name)); } } else if(parent_ != nullptr) { diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 41a155f94..d22c2724a 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -352,9 +352,7 @@ TEST_CASE("app_roundtrip_parse_normal_fail") { std::size_t pstring_start{0}; try { pstring_start = fuzzdata.add_custom_options(app.get(), parseData); - } - catch (const CLI::ConstructionError&/*ce*/) - { + } catch(const CLI::ConstructionError & /*ce*/) { CHECK(true); return; } From 2929ffee1c5ab69ad215a608e48a1faf3669882a Mon Sep 17 00:00:00 2001 From: Philip Top Date: Mon, 19 May 2025 07:08:42 -0700 Subject: [PATCH 42/51] add fuzz_fail file11 --- tests/fuzzFail/round_trip_custom11 | Bin 0 -> 575 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fuzzFail/round_trip_custom11 diff --git a/tests/fuzzFail/round_trip_custom11 b/tests/fuzzFail/round_trip_custom11 new file mode 100644 index 0000000000000000000000000000000000000000..e1dd987c62ad3b041234aefe4734e39fd13298ab GIT binary patch literal 575 zcmZ`$!AiqG5Y0L7B>jO<6gHuz2Gm`;o7Nu?&))r$9>ibp>|cm? zXEwG5qC;jjv&_7C^Hx>2#lk3~?##Td>g%N&EA=3Sk%f|Sb%p$Oc61;*=9*3teq94t zn4z)$G)3fqQcAa?G|j-5*f`_Z4ayMTK3*p8fWFcD8d~c(j`zsB_7oB>D22$lGeFa< zmQya*^YyZ@Qu@YbvnYy?$HbUCp@i)unFhyzx*QQX3lL@6MPufK09@i6^fAUE2QL;A zuZ~%tiLVOl!=w>tyLOeq#yx`y2{^+=8^;mz3_EjUngnG60Up%uutVrG*;NjIglrF# qx+mmT4%lhb2a=Dz$?WLsbIVo{soLBpbo}ukq;XG`f4TfVs`v&QM41}^ literal 0 HcmV?d00001 From 818951af62d6571568c3c2dbe3006a54a1b91825 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Tue, 20 May 2025 04:53:49 -0700 Subject: [PATCH 43/51] properly handle reversed arguments in config files. --- fuzz/fuzzApp.cpp | 43 ++++++++++++++++++++------------- include/CLI/impl/Config_inl.hpp | 4 +++ tests/FuzzFailTest.cpp | 2 +- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 98af0eb76..253d292d5 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -152,6 +152,26 @@ std::shared_ptr FuzzApp::generateApp() { return fApp; } +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<<":"<" << prefix<<":"<string[" << ii << "]:vstrD[" << jj - << "]=" << static_cast(res[ii][jj]) << ", other.vstrD[" << jj - << "]=" << static_cast(other.vstrD[ii][jj]) << '\n'; - } else { - std::cout << "string[" << ii << "]:vstrD[" << jj - << "]=" << static_cast(res[ii][jj]) << '\n'; - } - } + print_string_comparison(res[ii],other.vstrD[ii],std::string("string[")+std::to_string(ii)+']',"vstrD","other.vstrD"); + } } } @@ -340,6 +345,10 @@ bool FuzzApp::compare(const FuzzApp &other, bool print_error) const { for(std::size_t ii = 0; ii < custom_string_options.size(); ++ii) { 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; } } diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index abaf57c0d..0e363a5e6 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -553,6 +553,10 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, } auto results = opt->reduced_results(); + if (results.size()>1 && opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Reverse) + { + std::reverse(results.begin(), results.end()); + } std::string value = detail::ini_join(results, arraySeparator, arrayStart, arrayEnd, stringQuote, literalQuote); diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index d22c2724a..47ff0cc47 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -313,7 +313,7 @@ TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(1, 11)); + int index = GENERATE(range(11, 12)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); From c39a005ae84c247dda1c60d01622d52b0cae736f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:54:35 +0000 Subject: [PATCH 44/51] style: pre-commit.ci fixes --- fuzz/fuzzApp.cpp | 40 +++++++++++++++++++-------------- include/CLI/impl/Config_inl.hpp | 3 +-- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 253d292d5..acb533a3b 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -152,23 +152,23 @@ std::shared_ptr FuzzApp::generateApp() { return fApp; } -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) -{ +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<<":"<" << prefix<<":"<" << prefix << ":" << s1name << "[" << jj << "]=" << static_cast(s1[jj]) << ", " + << s2name << "[" << jj << "]=" << static_cast(s2[jj]) << '\n'; } else { - std::cout << prefix<<":"<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"); + 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; } diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 0e363a5e6..ccb33c77c 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -553,8 +553,7 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, } auto results = opt->reduced_results(); - if (results.size()>1 && opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Reverse) - { + if(results.size() > 1 && opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Reverse) { std::reverse(results.begin(), results.end()); } std::string value = From ba4a6a01edc2a5c1ecfc9edf2797f84bc5ba9395 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Tue, 20 May 2025 05:01:36 -0700 Subject: [PATCH 45/51] add fuzz_fail file12 --- tests/fuzzFail/round_trip_custom12 | Bin 0 -> 850 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fuzzFail/round_trip_custom12 diff --git a/tests/fuzzFail/round_trip_custom12 b/tests/fuzzFail/round_trip_custom12 new file mode 100644 index 0000000000000000000000000000000000000000..218b62387e11748227659b115953d67ec3614ad4 GIT binary patch literal 850 zcmdr~!AiqG5G{C-S^NiYq1Lq_BBJcZ23kFO^B!6g3zZE`oQj?bUOWr_Ob^lz=~?hB zhy-0{*Mvj@-n=-6-M91J%r0+MM3XR9LWxT?8b{;vX(|uIHFp#bMOO*2_o?;!DP>6J zr>dip%rhmT5S47tuyyjr0hb}Xbr8HY+AGY^9A_|^O~V8LNq0uNHh5OnASqEbF)U{v zL(Yb`X*Agi_yvHm(T9z;RdAw zDFFzBtoNzc5%!l$GGM_L7aZ>LJRhJ2zJppjt7uYK_J3XcVa6Z3=)`^|y5<}DS=6#& vzGE}{%{A9~uf-m(7-K4V*ybsxx#8 Date: Wed, 21 May 2025 05:36:50 -0700 Subject: [PATCH 46/51] add flag checks on positional arguments --- include/CLI/App.hpp | 3 + include/CLI/impl/App_inl.hpp | 132 ++++++++++-------- tests/FuzzFailTest.cpp | 8 +- ...{round_trip_custom12 => parse_fail_check5} | Bin 4 files changed, 86 insertions(+), 57 deletions(-) rename tests/fuzzFail/{round_trip_custom12 => parse_fail_check5} (100%) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 0e23a06c5..08488851d 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -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 &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 &args, bool &positional_only); diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index 97c8a52ff..4907a0097 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -1496,6 +1496,67 @@ CLI11_INLINE void App::_parse_config(const std::vector &args) { } } +CLI11_INLINE bool App::_add_flag_like_result(Option* op, const ConfigItem &item, const std::vector &inputs) +{ + if(item.inputs.size() <= 1) { + // Flag parsing + auto res = config_formatter_->to_flag(item); + bool converted{false}; + if(op->get_disable_flag_override()) { + auto val = detail::to_flag_value(res); + if(val == 1) { + res = op->get_flag_value(item.name, "{}"); + converted = true; + } + } + + if(!converted) { + errno = 0; + if(res != "{}" || op->get_expected_max() <= 1) { + res = op->get_flag_value(item.name, res); + } + } + + op->add_result(res); + return true; + } + if(static_cast(inputs.size()) > op->get_items_expected_max() && + op->get_multi_option_policy() != MultiOptionPolicy::TakeAll) { + if(op->get_items_expected_max() > 1) { + throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), inputs.size()); + } + + if(!op->get_disable_flag_override()) { + throw ConversionError::TooManyInputsFlag(item.fullname()); + } + // if the disable flag override is set then we must have the flag values match a known flag value + // this is true regardless of the output value, so an array input is possible and must be accounted for + for(const auto &res : inputs) { + bool valid_value{false}; + if(op->default_flag_values_.empty()) { + if(res == "true" || res == "false" || res == "1" || res == "0") { + valid_value = true; + } + } else { + for(const auto &valid_res : op->default_flag_values_) { + if(valid_res.second == res) { + valid_value = true; + break; + } + } + } + + if(valid_value) { + op->add_result(res); + } else { + throw InvalidError("invalid flag argument given"); + } + } + return true; + } + return false; +} + CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t level) { if(level < item.parents.size()) { @@ -1580,60 +1641,8 @@ CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t } const std::vector &inputs = (useBuffer) ? buffer : item.inputs; if(op->get_expected_min() == 0) { - if(item.inputs.size() <= 1) { - // Flag parsing - auto res = config_formatter_->to_flag(item); - bool converted{false}; - if(op->get_disable_flag_override()) { - auto val = detail::to_flag_value(res); - if(val == 1) { - res = op->get_flag_value(item.name, "{}"); - converted = true; - } - } - - if(!converted) { - errno = 0; - if(res != "{}" || op->get_expected_max() <= 1) { - res = op->get_flag_value(item.name, res); - } - } - - op->add_result(res); - return true; - } - if(static_cast(inputs.size()) > op->get_items_expected_max() && - op->get_multi_option_policy() != MultiOptionPolicy::TakeAll) { - if(op->get_items_expected_max() > 1) { - throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), inputs.size()); - } - - if(!op->get_disable_flag_override()) { - throw ConversionError::TooManyInputsFlag(item.fullname()); - } - // if the disable flag override is set then we must have the flag values match a known flag value - // this is true regardless of the output value, so an array input is possible and must be accounted for - for(const auto &res : inputs) { - bool valid_value{false}; - if(op->default_flag_values_.empty()) { - if(res == "true" || res == "false" || res == "1" || res == "0") { - valid_value = true; - } - } else { - for(const auto &valid_res : op->default_flag_values_) { - if(valid_res.second == res) { - valid_value = true; - break; - } - } - } - - if(valid_value) { - op->add_result(res); - } else { - throw InvalidError("invalid flag argument given"); - } - } + if (_add_flag_like_result(op, item, inputs)) + { return true; } } @@ -1762,7 +1771,20 @@ CLI11_INLINE bool App::_parse_positional(std::vector &args, bool ha if(posOpt->get_trigger_on_parse() && posOpt->current_option_state_ == Option::option_state::callback_run) { posOpt->clear(); } - posOpt->add_result(positional); + if(posOpt->get_expected_min() == 0) { + ConfigItem item; + item.name=posOpt->pname_; + item.inputs.push_back(positional); + if (!_add_flag_like_result(posOpt, item, item.inputs)) + { + posOpt->add_result(positional); + } + } + else + { + posOpt->add_result(positional); + } + if(posOpt->get_trigger_on_parse()) { posOpt->run_callback(); } diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 47ff0cc47..68cf4ea74 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -109,6 +109,7 @@ TEST_CASE("app_file_roundtrip") { auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); int index = GENERATE(range(1, 41)); + //int index = GENERATE(range(8, 9)); std::string optionString, flagString; auto parseData = loadFailureFile("fuzz_app_file_fail", index); if(parseData.size() > 25) { @@ -148,6 +149,7 @@ TEST_CASE("app_file_roundtrip") { result = fuzzdata2.compare(fuzzdata); } */ + INFO("Failure in test case "< 0) { app->parse(parseData.substr(pstring_start)); diff --git a/tests/fuzzFail/round_trip_custom12 b/tests/fuzzFail/parse_fail_check5 similarity index 100% rename from tests/fuzzFail/round_trip_custom12 rename to tests/fuzzFail/parse_fail_check5 From 413e662d8f0e0a0219d1608075f8ffc89239268a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:37:14 +0000 Subject: [PATCH 47/51] style: pre-commit.ci fixes --- include/CLI/App.hpp | 2 +- include/CLI/impl/App_inl.hpp | 20 ++++++++------------ tests/FuzzFailTest.cpp | 8 ++++---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 08488851d..ae9734c33 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -1323,7 +1323,7 @@ class App { 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 &inputs); + bool _add_flag_like_result(Option *op, const ConfigItem &item, const std::vector &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 diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index 4907a0097..8c74d701e 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -1496,8 +1496,8 @@ CLI11_INLINE void App::_parse_config(const std::vector &args) { } } -CLI11_INLINE bool App::_add_flag_like_result(Option* op, const ConfigItem &item, const std::vector &inputs) -{ +CLI11_INLINE bool +App::_add_flag_like_result(Option *op, const ConfigItem &item, const std::vector &inputs) { if(item.inputs.size() <= 1) { // Flag parsing auto res = config_formatter_->to_flag(item); @@ -1521,7 +1521,7 @@ CLI11_INLINE bool App::_add_flag_like_result(Option* op, const ConfigItem &item return true; } if(static_cast(inputs.size()) > op->get_items_expected_max() && - op->get_multi_option_policy() != MultiOptionPolicy::TakeAll) { + op->get_multi_option_policy() != MultiOptionPolicy::TakeAll) { if(op->get_items_expected_max() > 1) { throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), inputs.size()); } @@ -1641,8 +1641,7 @@ CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t } const std::vector &inputs = (useBuffer) ? buffer : item.inputs; if(op->get_expected_min() == 0) { - if (_add_flag_like_result(op, item, inputs)) - { + if(_add_flag_like_result(op, item, inputs)) { return true; } } @@ -1773,18 +1772,15 @@ CLI11_INLINE bool App::_parse_positional(std::vector &args, bool ha } if(posOpt->get_expected_min() == 0) { ConfigItem item; - item.name=posOpt->pname_; + item.name = posOpt->pname_; item.inputs.push_back(positional); - if (!_add_flag_like_result(posOpt, item, item.inputs)) - { + if(!_add_flag_like_result(posOpt, item, item.inputs)) { posOpt->add_result(positional); } - } - else - { + } else { posOpt->add_result(positional); } - + if(posOpt->get_trigger_on_parse()) { posOpt->run_callback(); } diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 68cf4ea74..f346d88f2 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -109,7 +109,7 @@ TEST_CASE("app_file_roundtrip") { auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); int index = GENERATE(range(1, 41)); - //int index = GENERATE(range(8, 9)); + // int index = GENERATE(range(8, 9)); std::string optionString, flagString; auto parseData = loadFailureFile("fuzz_app_file_fail", index); if(parseData.size() > 25) { @@ -149,7 +149,7 @@ TEST_CASE("app_file_roundtrip") { result = fuzzdata2.compare(fuzzdata); } */ - INFO("Failure in test case "< 0) { app->parse(parseData.substr(pstring_start)); From 41956600ecd9ecb9b2af1a49a0e8fbc17373b6b0 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Wed, 21 May 2025 06:48:19 -0700 Subject: [PATCH 48/51] add fuzz_fail file12 --- tests/fuzzFail/round_trip_custom12 | Bin 0 -> 259 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fuzzFail/round_trip_custom12 diff --git a/tests/fuzzFail/round_trip_custom12 b/tests/fuzzFail/round_trip_custom12 new file mode 100644 index 0000000000000000000000000000000000000000..40b8bca6e165dacebac7a8b58392fc3e7d6ebc6d GIT binary patch literal 259 zcmcCX%SlYnx5>B3%}>cp%Sb2sfB*mg^tY+_|GzvR zB$SquUr=JGWTPH#nxI>4;%DsaQ)OrnkXTfl>RMEkUo^9}+|EWfu^6bz1c;45Rsjvy zRflO$Ot&im8B?B^e(3*y9d2$A2Pl{TrT_ouj^#?%;nr2=X3*u*VITrs~eyCwwK)ZLRB?6rV0IDWPP5=M^ literal 0 HcmV?d00001 From 50e90e984c7cc5d76557ecbb0cd941a09f852d85 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Wed, 21 May 2025 06:57:11 -0700 Subject: [PATCH 49/51] fix seg fault possibility --- include/CLI/impl/App_inl.hpp | 5 ++++- tests/FuzzFailTest.cpp | 2 +- .../{round_trip_custom12 => parse_fail_check6} | Bin 3 files changed, 5 insertions(+), 2 deletions(-) rename tests/fuzzFail/{round_trip_custom12 => parse_fail_check6} (100%) diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index 8c74d701e..01609712b 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -1782,7 +1782,10 @@ CLI11_INLINE bool App::_parse_positional(std::vector &args, bool ha } if(posOpt->get_trigger_on_parse()) { - posOpt->run_callback(); + if (!posOpt->empty()) + { + posOpt->run_callback(); + } } args.pop_back(); diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index f346d88f2..5755acf73 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -350,7 +350,7 @@ TEST_CASE("app_roundtrip_parse_normal_fail") { // like HorribleErrors CLI::FuzzApp fuzzdata; auto app = fuzzdata.generateApp(); - int index = GENERATE(range(1, 6)); + int index = GENERATE(range(1, 7)); auto parseData = loadFailureFile("parse_fail_check", index); std::size_t pstring_start{0}; try { diff --git a/tests/fuzzFail/round_trip_custom12 b/tests/fuzzFail/parse_fail_check6 similarity index 100% rename from tests/fuzzFail/round_trip_custom12 rename to tests/fuzzFail/parse_fail_check6 From b200e34c5579f0541f1b691eed21c715e522801c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 13:57:31 +0000 Subject: [PATCH 50/51] style: pre-commit.ci fixes --- include/CLI/impl/App_inl.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index 01609712b..05557e171 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -1782,8 +1782,7 @@ CLI11_INLINE bool App::_parse_positional(std::vector &args, bool ha } if(posOpt->get_trigger_on_parse()) { - if (!posOpt->empty()) - { + if(!posOpt->empty()) { posOpt->run_callback(); } } From 5a35a807cbee9ff70dc7129fc3958b12a1780b95 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Wed, 21 May 2025 17:02:20 -0700 Subject: [PATCH 51/51] clang-tidy fixes --- fuzz/fuzzApp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/fuzzApp.hpp b/fuzz/fuzzApp.hpp index a358d455d..296dd8baf 100644 --- a/fuzz/fuzzApp.hpp +++ b/fuzz/fuzzApp.hpp @@ -63,7 +63,7 @@ class FuzzApp { /** modify an option based on string*/ static void modify_option(CLI::Option *opt, const std::string &modifier); - bool support_config_file_only() const { return !non_config_required; } + CLI11_NODISCARD bool support_config_file_only() const { return !non_config_required; } int32_t val32{0}; int16_t val16{0}; int8_t val8{0};