Ver código fonte

Make driver fuzzing more robust for clang flags (#5845)

I'm not sure the target in use here will reliably crash over time, but
it does right now, and that seems reasonable...?

Example crash:

```
file_test: external/+llvm_project+llvm-project/clang/lib/Driver/ToolChains/Darwin.h:505: bool clang::driver::toolchains::Darwin::isTargetWatchOSBased() const: Assertion `TargetInitialized && "Target not initialized!"' failed.
```

Stack fragment:

```
...
#10 0x0000562ba07dec33 isTargetWatchOSBased /proc/self/cwd/external/+llvm_project+llvm-project/clang/lib/Driver/ToolChains/Darwin.h:505:5
#11 0x0000562ba07dec33 clang::driver::toolchains::DarwinClang::addClangWarningOptions(llvm::SmallVector<char const*, 16u>&) const /proc/self/cwd/external/+llvm_project+llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp:1188:7
#12 0x0000562ba072afc7 clang::driver::tools::Clang::ConstructJob(clang::driver::Compilation&, clang::driver::JobAction const&, clang::driver::InputInfo const&, llvm::SmallVector<clang::driver::InputInfo, 4u> const&, llvm::opt::ArgList const&, char const*) const /proc/self/cwd/external/+llvm_project+llvm-project/clang/lib/Driver/ToolChains/Clang.cpp:0:6
#13 0x0000562ba06306d8 clang::driver::Driver::BuildJobsForActionNoCache(clang::driver::Compilation&, clang::driver::Action const*, clang::driver::ToolChain const*, llvm::StringRef, bool, bool, char const*, std::__1::map<std::__1::pair<clang::driver::Action const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, llvm::SmallVector<clang::driver::InputInfo, 4u>, std::__1::less<std::__1::pair<clang::driver::Action const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>, std::__1::allocator<std::__1::pair<std::__1::pair<clang::driver::Action const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> const, llvm::SmallVector<clang::driver::InputInfo, 4u>>>>&, clang::driver::Action::OffloadKind) const /proc/self/cwd/external/+llvm_project+llvm-project/clang/lib/Driver/Driver.cpp:6083:10
...
#28 0x0000562b9e479d1f Carbon::BuildClangInvocation(Carbon::Diagnostics::Consumer&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, llvm::ArrayRef<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>) /proc/self/cwd/toolchain/base/clang_invocation.cpp:103:21
...
```

---------

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Jon Ross-Perkins 9 meses atrás
pai
commit
59619fa8eb

+ 1 - 0
testing/base/BUILD

@@ -80,6 +80,7 @@ cc_test(
         ":global_exe_path",
         ":gtest_main",
         ":source_gen_lib",
+        "//common:all_llvm_targets",
         "//common:set",
         "//toolchain/driver",
         "//toolchain/install:install_paths_test_helpers",

+ 1 - 0
toolchain/codegen/BUILD

@@ -16,6 +16,7 @@ cc_library(
     srcs = ["codegen.cpp"],
     hdrs = ["codegen.h"],
     deps = [
+        "//common:check",
         "@llvm-project//llvm:Core",
         "@llvm-project//llvm:MC",
         "@llvm-project//llvm:Support",

+ 2 - 4
toolchain/codegen/codegen.cpp

@@ -8,6 +8,7 @@
 #include <optional>
 #include <string>
 
+#include "common/check.h"
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Target/TargetOptions.h"
@@ -20,11 +21,8 @@ auto CodeGen::Make(llvm::Module* module, llvm::StringRef target_triple_str,
   std::string error;
   const llvm::Target* target =
       llvm::TargetRegistry::lookupTarget(target_triple_str, error);
+  CARBON_CHECK(target, "Target should be validated before codegen");
 
-  if (!target) {
-    *errors << "error: invalid target: " << error << "\n";
-    return {};
-  }
   llvm::Triple target_triple(target_triple_str);
   module->setTargetTriple(target_triple);
 

+ 1 - 0
toolchain/diagnostics/diagnostic_kind.def

@@ -27,6 +27,7 @@ CARBON_DIAGNOSTIC_KIND(CompilePhaseFlagConflict)
 CARBON_DIAGNOSTIC_KIND(CompilePreludeManifestError)
 CARBON_DIAGNOSTIC_KIND(CompileInputNotRegularFile)
 CARBON_DIAGNOSTIC_KIND(CompileOutputFileOpenError)
+CARBON_DIAGNOSTIC_KIND(CompileTargetInvalid)
 CARBON_DIAGNOSTIC_KIND(FormatMultipleFilesToOneOutput)
 CARBON_DIAGNOSTIC_KIND(ToolFuzzingDisallowed)
 

+ 4 - 0
toolchain/driver/BUILD

@@ -4,6 +4,7 @@
 
 load("@rules_shell//shell:sh_test.bzl", "sh_test")
 load("//bazel/cc_rules:defs.bzl", "cc_binary", "cc_library", "cc_test")
+load("//bazel/cc_toolchains:defs.bzl", "cc_env")
 load("//testing/fuzzing:rules.bzl", "cc_fuzz_test")
 
 package(default_visibility = ["//visibility:public"])
@@ -62,6 +63,7 @@ cc_binary(
     srcs = ["compile_benchmark.cpp"],
     deps = [
         ":driver",
+        "//common:all_llvm_targets",
         "//testing/base:benchmark_main",
         "//testing/base:global_exe_path",
         "//testing/base:source_gen_lib",
@@ -81,6 +83,7 @@ sh_test(
         # The `$$` is repeated for Bazel escaping of `$`.
         "--benchmark_filter=/256$$",
     ],
+    env = cc_env(),
 )
 
 cc_library(
@@ -144,6 +147,7 @@ cc_library(
         "//toolchain/sem_ir:typed_insts",
         "//toolchain/source:source_buffer",
         "@llvm-project//llvm:Core",
+        "@llvm-project//llvm:MC",
         "@llvm-project//llvm:Support",
         "@llvm-project//llvm:TargetParser",
     ],

+ 18 - 0
toolchain/driver/compile_subcommand.cpp

@@ -15,6 +15,7 @@
 #include "common/vlog.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
+#include "llvm/MC/TargetRegistry.h"
 #include "toolchain/base/clang_invocation.h"
 #include "toolchain/base/timings.h"
 #include "toolchain/check/check.h"
@@ -844,6 +845,17 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
     return {.success = false};
   }
 
+  // Validate the target before passing it to Clang.
+  std::string target_error;
+  const llvm::Target* target = llvm::TargetRegistry::lookupTarget(
+      options_.codegen_options.target, target_error);
+  if (!target) {
+    CARBON_DIAGNOSTIC(CompileTargetInvalid, Error, "invalid target: {0}",
+                      std::string);
+    driver_env.emitter.Emit(CompileTargetInvalid, target_error);
+    return {.success = false};
+  }
+
   std::shared_ptr<clang::CompilerInvocation> clang_invocation;
   // Build a clang invocation. We do this regardless of whether we're running
   // check, because this is essentially performing further option validation,
@@ -862,6 +874,12 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
         // TODO: Decide if we want this.
         "-fPIE",
     };
+    if (driver_env.fuzzing && !options_.clang_args.empty()) {
+      // Parsing specific Clang arguments can reach deep into
+      // external libraries that aren't fuzz clean.
+      DisableFuzzingExternalLibraries(driver_env, "compile");
+      return {.success = false};
+    }
     for (auto str : options_.clang_args) {
       clang_path_and_args.push_back(str.str());
     }

+ 2 - 2
toolchain/driver/testdata/compile/fail_clang_args.carbon

@@ -2,7 +2,7 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-// ARGS: --include-diagnostic-kind compile --target=x86-pc-linux-gnu --clang-arg=-Wall --clang-arg=-Wextra foo.carbon -- -Wuninitialized -Wno-all -###
+// ARGS: --include-diagnostic-kind compile --target=x86_64-unknown-linux-gnu --clang-arg=-Wall --clang-arg=-Wextra foo.carbon -- -Wuninitialized -Wno-all -###
 //
 // SET-CAPTURE-CONSOLE-OUTPUT
 // SET-CHECK-SUBSET
@@ -13,6 +13,6 @@
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/driver/testdata/compile/fail_clang_args.carbon
 // CHECK:STDERR: {{.*}}clang version {{.*}}
 // CHECK:STDERR: InstalledDir: {{.*}}/toolchain/install/prefix_root/lib/carbon/../../lib/carbon/llvm/bin
-// CHECK:STDERR:  "{{.*}}/toolchain/install/prefix_root/lib/carbon/../../lib/carbon/llvm/bin/clang" "-cc1" {{.*}}"-triple" "x86-pc-linux-gnu" {{.*}}"-fsyntax-only" {{.*}} "-resource-dir" {{.*}} "-Wall" "-Wextra" "-Wuninitialized" "-Wno-all" {{.*}}
+// CHECK:STDERR:  "{{.*}}/toolchain/install/prefix_root/lib/carbon/../../lib/carbon/llvm/bin/clang" "-cc1" {{.*}}"-triple" "x86_64-unknown-linux-gnu" {{.*}}"-fsyntax-only" {{.*}} "-resource-dir" {{.*}} "-Wall" "-Wextra" "-Wuninitialized" "-Wno-all" {{.*}}
 
 // --- foo.carbon

+ 15 - 0
toolchain/driver/testdata/fail_fuzzing_invalid_clang_arg.carbon

@@ -0,0 +1,15 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// ARGS: --include-diagnostic-kind --fuzzing compile nonexistent -- --target=mips64-a-ios
+//
+// SET-CAPTURE-CONSOLE-OUTPUT
+// clang-format off
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/driver/testdata/fail_fuzzing_invalid_clang_arg.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/driver/testdata/fail_fuzzing_invalid_clang_arg.carbon
+// CHECK:STDERR: error: preventing fuzzing of `compile` subcommand due to external library [ToolFuzzingDisallowed]
+// CHECK:STDERR:

+ 15 - 0
toolchain/driver/testdata/fail_fuzzing_invalid_target.carbon

@@ -0,0 +1,15 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// ARGS: --include-diagnostic-kind --fuzzing compile nonexistent --target=mips64-a-ios
+//
+// SET-CAPTURE-CONSOLE-OUTPUT
+// clang-format off
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/driver/testdata/fail_fuzzing_invalid_target.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/driver/testdata/fail_fuzzing_invalid_target.carbon
+// CHECK:STDERR: error: invalid target: No available targets are compatible with triple "mips64-a-ios" [CompileTargetInvalid]
+// CHECK:STDERR:

+ 1 - 0
toolchain/sem_ir/BUILD

@@ -292,6 +292,7 @@ cc_test(
     size = "small",
     srcs = ["yaml_test.cpp"],
     deps = [
+        "//common:all_llvm_targets",
         "//common:ostream",
         "//common:raw_string_ostream",
         "//testing/base:global_exe_path",