From 150057f260a012305faa0c9da7c8fb755c6fe8d6 Mon Sep 17 00:00:00 2001 From: pk19604014 <95385881+pk19604014@users.noreply.github.com> Date: Mon, 2 May 2022 10:36:21 -0400 Subject: [PATCH] Added GetRunfilesFile() to be able to reliably determine prelude location under various invocation scenarios The logic is using bazel Runfiles API per Jon's suggestion. One of the scenarios used by the fuzzing framework is to place the binary and its runfiles into a folder, resulting in a directory layout like this: [temp dir] fuzzer fuzzer.runfiles/ Tested: bazel test -c opt explorer/fuzzing:explorer_fuzzer bazel build -c opt explorer/fuzzing:explorer_fuzzer + run the binary from various locations --- explorer/fuzzing/BUILD | 2 ++ explorer/fuzzing/fuzzer_util.cpp | 25 ++++++++++++++++++++++++- explorer/fuzzing/fuzzer_util.h | 8 ++++++++ explorer/fuzzing/fuzzer_util_test.cpp | 13 +++++++++++++ scripts/fix_cc_deps.py | 3 +++ 5 files changed, 50 insertions(+), 1 deletion(-) 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