diff --git a/explorer/fuzzing/BUILD b/explorer/fuzzing/BUILD index ff0b47d592f9..2a8136c51da9 100644 --- a/explorer/fuzzing/BUILD +++ b/explorer/fuzzing/BUILD @@ -25,11 +25,13 @@ cc_library( hdrs = ["fuzzer_util.h"], deps = [ "//common:check", + "//common:error", "//common/fuzzing:carbon_cc_proto", "//common/fuzzing:proto_to_carbon_lib", "//explorer/interpreter:exec_program", "//explorer/syntax", "//explorer/syntax:prelude", + "@bazel_tools//tools/cpp/runfiles", "@com_google_protobuf//:protobuf_headers", "@llvm-project//llvm:Support", ], diff --git a/explorer/fuzzing/fuzzer_util.cpp b/explorer/fuzzing/fuzzer_util.cpp index ede66c51ffbc..b697c489595f 100644 --- a/explorer/fuzzing/fuzzer_util.cpp +++ b/explorer/fuzzing/fuzzer_util.cpp @@ -9,7 +9,10 @@ #include "explorer/interpreter/exec_program.h" #include "explorer/syntax/parse.h" #include "explorer/syntax/prelude.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include "tools/cpp/runfiles/runfiles.h" namespace Carbon { @@ -21,6 +24,23 @@ fn Main() -> i32 { } )"; +auto Internal::GetRunfilesFile(const std::string& file) + -> ErrorOr { + using bazel::tools::cpp::runfiles::Runfiles; + std::string error; + // `Runfiles::Create()` fails if passed an empty `argv0`. + std::unique_ptr runfiles(Runfiles::Create( + /*argv0=*/llvm::sys::fs::getMainExecutable(nullptr, nullptr), &error)); + if (runfiles == nullptr) { + return Error(error); + } + std::string full_path = runfiles->Rlocation(file); + if (!llvm::sys::fs::exists(full_path)) { + return ErrorBuilder() << full_path << " doesn't exist"; + } + return full_path; +} + auto ProtoToCarbonWithMain(const Fuzzing::CompilationUnit& compilation_unit) -> std::string { const bool has_main = std::any_of( @@ -43,7 +63,10 @@ void ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit) { llvm::errs() << "Parsing failed: " << ast.error().message() << "\n"; return; } - AddPrelude("explorer/data/prelude.carbon", &arena, &ast->declarations); + const ErrorOr prelude_path = + Internal::GetRunfilesFile("carbon/explorer/data/prelude.carbon"); + CHECK(prelude_path.ok()) << prelude_path.error().message(); + AddPrelude(*prelude_path, &arena, &ast->declarations); const ErrorOr result = ExecProgram(&arena, *ast, /*trace_stream=*/std::nullopt); if (!result.ok()) { diff --git a/explorer/fuzzing/fuzzer_util.h b/explorer/fuzzing/fuzzer_util.h index 42ee655ab687..42f4bbd82ab0 100644 --- a/explorer/fuzzing/fuzzer_util.h +++ b/explorer/fuzzing/fuzzer_util.h @@ -5,6 +5,7 @@ #ifndef EXPLORER_FUZZING_FUZZER_UTIL_H_ #define EXPLORER_FUZZING_FUZZER_UTIL_H_ +#include "common/error.h" #include "common/fuzzing/carbon.pb.h" namespace Carbon { @@ -17,6 +18,13 @@ auto ProtoToCarbonWithMain(const Fuzzing::CompilationUnit& compilation_unit) // Parses and executes a fuzzer-generated program. void ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit); +namespace Internal { + +// Returns a full path for a file under bazel runfiles. +// Exposed for testing. +auto GetRunfilesFile(const std::string& file) -> ErrorOr; + +} // namespace Internal } // namespace Carbon #endif // EXPLORER_FUZZING_FUZZER_UTIL_H_ diff --git a/explorer/fuzzing/fuzzer_util_test.cpp b/explorer/fuzzing/fuzzer_util_test.cpp index a1e3ff219e42..3dd4fbb4bae4 100644 --- a/explorer/fuzzing/fuzzer_util_test.cpp +++ b/explorer/fuzzing/fuzzer_util_test.cpp @@ -36,6 +36,19 @@ TEST(FuzzerUtilTest, RunFuzzerOnCorpus) { EXPECT_GT(file_count, 0); } +TEST(FuzzerUtilTest, GetRunfilesFile) { + EXPECT_THAT(*Internal::GetRunfilesFile( + "carbon/explorer/fuzzing/fuzzer_corpus/empty.textproto"), + testing::EndsWith("/explorer/fuzzing/fuzzer_corpus/" + "empty.textproto")); + EXPECT_THAT(Internal::GetRunfilesFile( + "explorer/fuzzing/fuzzer_corpus/empty.textproto") + .error() + .message(), + testing::EndsWith("fuzzer_util_test.runfiles/explorer/fuzzing/" + "fuzzer_corpus/empty.textproto doesn't exist")); +} + } // namespace } // namespace Carbon::Testing diff --git a/scripts/fix_cc_deps.py b/scripts/fix_cc_deps.py index b0ce4c6e45b2..7452c2067b7e 100755 --- a/scripts/fix_cc_deps.py +++ b/scripts/fix_cc_deps.py @@ -36,6 +36,9 @@ EXTERNAL_REPOS: Dict[str, Callable[[str], str]] = { "@com_google_libprotobuf_mutator": lambda x: re.sub( "^(.*:)", "libprotobuf_mutator/", x ), + # @bazel_tools//tools/cpp/runfiles:runfiles.h -> + # tools/cpp/runfiles/runfiles.h + "@bazel_tools": lambda x: re.sub(":", "/", x), } # TODO: proto rules are aspect-based and their generated files don't show up in