Expose API to parse known absl flags. This change makes it easier for consumers such as Chromium to use fuzztest. It changes argument handling in two ways: 1) It exposes a new 'InitAbslFlagsForFuzztest' API. Chromium's test suites otherwise needed to call into absl flags directly to initialize absl's command line; this was problematic in projects where absl flags are not normally used. Integration of fuzztest is easier if we need to call only fuzztest APIs instead of absl flags directly. A key point of this new API is that it does not call absl::ParseCommandLine, but instead absl::ParseAbseilFlagsOnly. This ignores unknown command-line options, which is important in environments where other code may use non-absl parsing of command lines. 2) fuzztest_gtest_main is amended to use the above function instead of absl::ParseCommandLine. This is because, when used with libfuzzer or other non-centipede fuzzing engines, those fuzzing engines themselves absorb command linm arguments, and thus the previous use of absl::ParseCommandLine always failed unless a complex '-undefok=' argument was constructed listing all the possible options that could be passed to libfuzzer. As an indication of the complexity here, in a typical Chromium test, command-line arguments may flow to four places: * FuzzTest's absl flags * libfuzzer, passed there via InitFuzzTest (or some other fuzzing engine) * Chromium's own test frameworks (flags like --single-process-tests) * Chromium's underlying code, e.g. for enabling runtime features or disabling the sandbox. Because of the many areas of code handling command line arguments, it's not practical to declare them all in advance either using absl flags, nor using `-undefok` and that's why it's important that FuzzTest uses absl::ParseAbseilFlagsOnly to avoid erroring in the face of unknown extra command line arguments. This CL does not fix a third problem in this area, which is that the fuzztest engine stores the given argc and argv and assumes it never subsequently changes - this assumption is wrong in projects such as Chromium where other layers of software may absorb and modify the command line later, and results in use-after-return bugs. However this can be easily worked around by storing an extra copy of the original argc and argv for use by fuzztest, disregarding subsequent changes. PiperOrigin-RevId: 625785463
diff --git a/fuzztest/BUILD b/fuzztest/BUILD index fd4eae7..38990c3 100644 --- a/fuzztest/BUILD +++ b/fuzztest/BUILD
@@ -109,6 +109,7 @@ ":registry", ":runtime", "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", "@com_google_absl//absl/flags:reflection", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format",
diff --git a/fuzztest/fuzztest_gtest_main.cc b/fuzztest/fuzztest_gtest_main.cc index 1c53586..f4aea2d 100644 --- a/fuzztest/fuzztest_gtest_main.cc +++ b/fuzztest/fuzztest_gtest_main.cc
@@ -21,7 +21,10 @@ int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); - absl::ParseCommandLine(argc, argv); + // We call fuzztest::ParseAbslFlagsrather than absl::ParseCommandLine + // since the latter would complain about any unknown flags that need + // to be passed to legacy fuzzing engines (e.g. libfuzzer). + fuzztest::ParseAbslFlags(argc, argv); fuzztest::InitFuzzTest(&argc, &argv); return RUN_ALL_TESTS(); }
diff --git a/fuzztest/init_fuzztest.cc b/fuzztest/init_fuzztest.cc index dda5f94..9d3db8e 100644 --- a/fuzztest/init_fuzztest.cc +++ b/fuzztest/init_fuzztest.cc
@@ -11,6 +11,7 @@ #include "gtest/gtest.h" #include "absl/flags/flag.h" +#include "absl/flags/parse.h" #include "absl/flags/reflection.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" @@ -229,4 +230,10 @@ internal::Runtime::instance().SetRunMode(run_mode); } +void ParseAbslFlags(int argc, char** argv) { + std::vector<char*> positional_args; + std::vector<absl::UnrecognizedFlag> unrecognized_flags; + absl::ParseAbseilFlagsOnly(argc, argv, positional_args, unrecognized_flags); +} + } // namespace fuzztest
diff --git a/fuzztest/init_fuzztest.h b/fuzztest/init_fuzztest.h index df5da51..e33ca39 100644 --- a/fuzztest/init_fuzztest.h +++ b/fuzztest/init_fuzztest.h
@@ -8,6 +8,18 @@ namespace fuzztest { +// Initializes Abseil flags such that FuzzTest can rely upon them. +// It initializes all Abseil flags (not just FuzzTest ones). +// It does not do anything with non-Abseil flags and will not result +// in an error or failure if there are other flags on the command line +// (as there might be especially if you are using a non-centipede +// fuzzing engine). +// This should be called only if you have no other code initializing +// Abseil flags from the command line elsewhere (such as +// absl::ParseCommandLine()). +// It does not change the command line (argv); only reads it. +void ParseAbslFlags(int argc, char** argv); + // Initializes FuzzTest. Handles the FuzzTest related flags and registers // FUZZ_TEST-s in the binary as GoogleTest TEST-s. // @@ -17,6 +29,8 @@ // https://llvm.org/docs/LibFuzzer.html#using-libfuzzer-as-a-library // // REQUIRES: `main()` has started before calling this function. +// REQUIRES: Abseil flags have been inited, either using +// ParseAbslFlags or some other means void InitFuzzTest(int* argc, char*** argv); // Returns a list of all registered fuzz test names in the form of