Преглед изворни кода

Exempt the `clang` subcommand when fuzzing. (#4468)

This teaches the driver library to track when its being used with
fuzzing and disables the `clang` subcommand from actually running Clang.

The Clang libraries have a large backlog of fuzzer-found issues that
isn't being actively reduced, so we can't productively fuzz into it.
This lets us more productively fuzz at the top level.

This is also available on the command line itself, which should be
useful if anyone wants to fuzz Carbon from the command line using tools
like AFL -- they can inject this flag to avoid getting noise from the
fuzzer hitting known issues in Clang.
Chandler Carruth пре 1 година
родитељ
комит
954441c358

+ 9 - 0
toolchain/driver/clang_subcommand.cpp

@@ -44,6 +44,15 @@ Arguments passed to Clang.
 auto ClangSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
   std::string target = llvm::sys::getDefaultTargetTriple();
   ClangRunner runner(driver_env.installation, target, driver_env.vlog_stream);
+
+  // Don't run Clang when fuzzing, it is known to not be reliable under fuzzing
+  // due to many unfixed issues.
+  if (driver_env.fuzzing) {
+    driver_env.error_stream
+        << "error: cannot run `clang` subcommand productively when fuzzing\n";
+    return {.success = false};
+  }
+
   return {.success = runner.Run(options_.args)};
 }
 

+ 14 - 0
toolchain/driver/driver.cpp

@@ -24,6 +24,7 @@ struct Options {
   auto Build(CommandLine::CommandBuilder& b) -> void;
 
   bool verbose;
+  bool fuzzing;
 
   ClangSubcommand clang;
   CompileSubcommand compile;
@@ -63,6 +64,13 @@ auto Options::Build(CommandLine::CommandBuilder& b) -> void {
       },
       [&](CommandLine::FlagBuilder& arg_b) { arg_b.Set(&verbose); });
 
+  b.AddFlag(
+      {
+          .name = "fuzzing",
+          .help = "Configure the command line for fuzzing.",
+      },
+      [&](CommandLine::FlagBuilder& arg_b) { arg_b.Set(&fuzzing); });
+
   b.AddSubcommand(ClangOptions::Info, [&](CommandLine::CommandBuilder& sub_b) {
     clang.BuildOptions(sub_b);
     sub_b.Do([&] { subcommand = &clang; });
@@ -109,8 +117,14 @@ auto Driver::RunCommand(llvm::ArrayRef<llvm::StringRef> args) -> DriverResult {
     // Note this implies streamed output in order to interleave.
     driver_env_.vlog_stream = &driver_env_.error_stream;
   }
+  if (options.fuzzing) {
+    SetFuzzing();
+  }
+
   CARBON_CHECK(options.subcommand != nullptr);
   return options.subcommand->Run(driver_env_);
 }
 
+auto Driver::SetFuzzing() -> void { driver_env_.fuzzing = true; }
+
 }  // namespace Carbon

+ 4 - 0
toolchain/driver/driver.h

@@ -38,6 +38,10 @@ class Driver {
   // error stream (stderr by default).
   auto RunCommand(llvm::ArrayRef<llvm::StringRef> args) -> DriverResult;
 
+  // Configure the driver for fuzzing. This allows specific commands to error
+  // rather than perform operations that aren't well behaved during fuzzing.
+  auto SetFuzzing() -> void;
+
  private:
   DriverEnv driver_env_;
 };

+ 3 - 0
toolchain/driver/driver_env.h

@@ -25,6 +25,9 @@ struct DriverEnv {
 
   // For CARBON_VLOG.
   llvm::raw_pwrite_stream* vlog_stream = nullptr;
+
+  // Tracks when the driver is being fuzzed.
+  bool fuzzing = false;
 };
 
 }  // namespace Carbon

+ 1 - 0
toolchain/driver/driver_fuzzer.cpp

@@ -82,6 +82,7 @@ extern "C" auto LLVMFuzzerTestOneInput(const unsigned char* data, size_t size)
   TestRawOstream error_stream;
   llvm::raw_null_ostream dest;
   Driver d(fs, install_paths, dest, error_stream);
+  d.SetFuzzing();
   if (!d.RunCommand(args).success) {
     auto str = error_stream.TakeStr();
     // TODO: Fix command_line to use `error`, switch back to `find`.