From d12583fc083ef4386d77af05248e9062f2f051ea Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Fri, 21 Apr 2023 08:23:58 -0700 Subject: [PATCH] Do cleanup on explorer fuzzing infrastructure. (#2790) I'm partly doing this because the current setup would be difficult to share with the toolchain. e.g., ProtoToCarbon isn't explorer-specific, but the only way to run it via CLI is the explorer's fuzzverter. I want a separate tool. This change: - Adds a //common/fuzzing:proto_to_carbon tool. - The rest of fuzzverter is now just //explorer/fuzzing:ast_to_proto. - The change simplifies overall handling and removes a LLVM CLI dependency. - Stops allowing unknown fields in the proto. - This has mostly led to forgetting to remove fuzzer inputs that were for removed features. - Moves more non-explorer-specific bits to //common/fuzzing. - Cleans up remaining pieces in //explorer/fuzzing - Merges the //explorer/fuzzing proto tests, which deduplicates AstToString copies. - These tests also had duplicate dependencies, etc -- and all complete in ~6s. - Updates and fixes regen_corpus which was previously broken by other changes. - Updates the README to reflect changes. - Removes obsolete proto-fuzzer build configuration (AFAICT this is no longer needed). --- .bazelrc | 3 - .../clang_cc_toolchain_config.bzl | 8 -- common/fuzzing/BUILD | 27 ++++ common/fuzzing/proto_to_carbon.cpp | 54 +++++--- common/fuzzing/proto_to_carbon.h | 7 +- common/fuzzing/proto_to_carbon_main.cpp | 51 +++++++ common/fuzzing/proto_to_carbon_test.cpp | 73 ++++++++++ explorer/fuzzing/BUILD | 85 +++--------- explorer/fuzzing/README.md | 82 +++++------- explorer/fuzzing/ast_to_proto.cpp | 14 +- explorer/fuzzing/ast_to_proto.h | 2 +- explorer/fuzzing/ast_to_proto_main.cpp | 66 +++++++++ explorer/fuzzing/ast_to_proto_test.cpp | 117 +++++++++++++--- explorer/fuzzing/clone_test.cpp | 73 ---------- explorer/fuzzing/explorer_fuzzer.cpp | 2 +- explorer/fuzzing/fuzzer_util.cpp | 44 +----- explorer/fuzzing/fuzzer_util.h | 17 +-- explorer/fuzzing/fuzzer_util_test.cpp | 28 +--- explorer/fuzzing/fuzzverter.cpp | 125 ------------------ explorer/fuzzing/proto_to_carbon_test.cpp | 64 --------- explorer/fuzzing/regen_corpus.py | 17 +-- 21 files changed, 432 insertions(+), 527 deletions(-) create mode 100644 common/fuzzing/proto_to_carbon_main.cpp create mode 100644 common/fuzzing/proto_to_carbon_test.cpp create mode 100644 explorer/fuzzing/ast_to_proto_main.cpp delete mode 100644 explorer/fuzzing/clone_test.cpp delete mode 100644 explorer/fuzzing/fuzzverter.cpp delete mode 100644 explorer/fuzzing/proto_to_carbon_test.cpp diff --git a/.bazelrc b/.bazelrc index bd2f837052e9..9b2b0008ef02 100644 --- a/.bazelrc +++ b/.bazelrc @@ -62,9 +62,6 @@ build:asan --features=asan # Configuration for enabling LibFuzzer (along with ASan). build:fuzzer --features=fuzzer -# Proto fuzzer specific configuration. -build:proto-fuzzer --features=proto-fuzzer - # Always allow tests to symbolize themselves with whatever `llvm-symbolize` is # in the users environment. build --test_env=ASAN_SYMBOLIZER_PATH diff --git a/bazel/cc_toolchains/clang_cc_toolchain_config.bzl b/bazel/cc_toolchains/clang_cc_toolchain_config.bzl index 77863a66b897..d1ae48d23db0 100644 --- a/bazel/cc_toolchains/clang_cc_toolchain_config.bzl +++ b/bazel/cc_toolchains/clang_cc_toolchain_config.bzl @@ -509,13 +509,6 @@ def _impl(ctx): )], ) - proto_fuzzer = feature( - name = "proto-fuzzer", - enabled = False, - requires = [feature_set(["nonhost"])], - implies = ["fuzzer"], - ) - # With clang 14 and lower, we expect it to be built with libc++ debug # support. In later LLVM versions, we expect the assertions define to work. if clang_version and clang_version <= 14: @@ -851,7 +844,6 @@ def _impl(ctx): asan, enable_asan_in_fastbuild, fuzzer, - proto_fuzzer, layering_check, module_maps, use_module_maps, diff --git a/common/fuzzing/BUILD b/common/fuzzing/BUILD index 2716717173ac..f3cdc3766ee0 100644 --- a/common/fuzzing/BUILD +++ b/common/fuzzing/BUILD @@ -25,6 +25,33 @@ cc_library( hdrs = ["proto_to_carbon.h"], deps = [ ":carbon_cc_proto", + "//common:error", "@llvm-project//llvm:Support", ], ) + +cc_binary( + name = "proto_to_carbon", + testonly = 1, + srcs = ["proto_to_carbon_main.cpp"], + deps = [ + ":carbon_cc_proto", + ":proto_to_carbon_lib", + "//common:bazel_working_dir", + "//common:error", + "@com_google_protobuf//:protobuf_headers", + "@llvm-project//llvm:Support", + ], +) + +cc_test( + name = "proto_to_carbon_test", + srcs = ["proto_to_carbon_test.cpp"], + deps = [ + ":carbon_cc_proto", + ":proto_to_carbon_lib", + "//common:error", + "//common:gtest_main", + "@com_google_googletest//:gtest", + ], +) diff --git a/common/fuzzing/proto_to_carbon.cpp b/common/fuzzing/proto_to_carbon.cpp index 72b7e9aac14b..df1b4f254449 100644 --- a/common/fuzzing/proto_to_carbon.cpp +++ b/common/fuzzing/proto_to_carbon.cpp @@ -4,6 +4,8 @@ #include "common/fuzzing/proto_to_carbon.h" +#include + #include #include "common/fuzzing/carbon.pb.h" @@ -966,28 +968,44 @@ static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration, } } -static auto ProtoToCarbon(const Fuzzing::CompilationUnit& compilation_unit, - llvm::raw_ostream& out) -> void { - out << "// Generated by proto_to_carbon.\n\n"; - out << "package "; - LibraryNameToCarbon(compilation_unit.package_statement(), out); - out << (compilation_unit.is_api() ? " api" : " impl") << ";\n"; - - if (!compilation_unit.declarations().empty()) { - out << "\n"; - for (const auto& declaration : compilation_unit.declarations()) { - DeclarationToCarbon(declaration, out); - out << "\n"; - } - } -} - -auto ProtoToCarbon(const Fuzzing::CompilationUnit& compilation_unit) +auto ProtoToCarbon(const Fuzzing::Carbon& proto, bool maybe_add_main) -> std::string { std::string source; llvm::raw_string_ostream out(source); - ProtoToCarbon(compilation_unit, out); + + out << "// Generated by proto_to_carbon.\n" + "package "; + const auto& unit = proto.compilation_unit(); + LibraryNameToCarbon(unit.package_statement(), out); + out << (unit.is_api() ? " api" : " impl") << ";\n\n"; + + bool has_main = false; + if (!unit.declarations().empty()) { + for (const auto& declaration : unit.declarations()) { + DeclarationToCarbon(declaration, out); + if (declaration.kind_case() == Fuzzing::Declaration::kFunction && + declaration.function().name().name() == "Main") { + has_main = true; + } + out << "\n"; + } + } + + if (maybe_add_main && !has_main) { + out << "fn Main() -> i32 { return 0; }\n"; + } + return source; } +auto ParseCarbonTextProto(const std::string& contents) + -> ErrorOr { + google::protobuf::TextFormat::Parser parser; + Fuzzing::Carbon carbon_proto; + if (!parser.ParseFromString(contents, &carbon_proto)) { + return ErrorBuilder() << "Couldn't parse Carbon text proto"; + } + return carbon_proto; +} + } // namespace Carbon diff --git a/common/fuzzing/proto_to_carbon.h b/common/fuzzing/proto_to_carbon.h index 0b906e3571cf..88196a297970 100644 --- a/common/fuzzing/proto_to_carbon.h +++ b/common/fuzzing/proto_to_carbon.h @@ -5,6 +5,7 @@ #ifndef CARBON_COMMON_FUZZING_PROTO_TO_CARBON_H_ #define CARBON_COMMON_FUZZING_PROTO_TO_CARBON_H_ +#include "common/error.h" #include "common/fuzzing/carbon.pb.h" namespace Carbon { @@ -14,9 +15,13 @@ namespace Carbon { // buffer is invalid (like a variable declaration with an empty `name` field). // This is done to reduce the number of inputs the fuzzer framework generates // when trying to produce lexically valid source. -auto ProtoToCarbon(const Fuzzing::CompilationUnit& compilation_unit) +auto ProtoToCarbon(const Fuzzing::Carbon& proto, bool maybe_add_main) -> std::string; +// Parses the textproto into a proto object. +auto ParseCarbonTextProto(const std::string& contents) + -> ErrorOr; + } // namespace Carbon #endif // CARBON_COMMON_FUZZING_PROTO_TO_CARBON_H_ diff --git a/common/fuzzing/proto_to_carbon_main.cpp b/common/fuzzing/proto_to_carbon_main.cpp new file mode 100644 index 000000000000..7598b033895d --- /dev/null +++ b/common/fuzzing/proto_to_carbon_main.cpp @@ -0,0 +1,51 @@ +// 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 + +// To convert a crashing input in text proto to Carbon source: +// `proto_to_carbon ` + +#include + +#include +#include +#include + +#include "common/bazel_working_dir.h" +#include "common/error.h" +#include "common/fuzzing/proto_to_carbon.h" + +namespace Carbon { + +auto Main(int argc, char** argv) -> ErrorOr { + Carbon::SetWorkingDirForBazel(); + + if (argc != 2) { + return Error("Syntax: proto_to_carbon "); + } + if (!std::filesystem::is_regular_file(argv[1])) { + return Error("Argument must be a file."); + } + + // Read the input file. + std::ifstream proto_file(argv[1]); + std::stringstream buffer; + buffer << proto_file.rdbuf(); + proto_file.close(); + + CARBON_ASSIGN_OR_RETURN(Fuzzing::Carbon proto, + Carbon::ParseCarbonTextProto(buffer.str())); + std::cout << Carbon::ProtoToCarbon(proto, /*maybe_add_main=*/true); + return Success(); +} + +} // namespace Carbon + +auto main(int argc, char** argv) -> int { + auto err = Carbon::Main(argc, argv); + if (!err.ok()) { + std::cerr << err.error().message() << "\n"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/common/fuzzing/proto_to_carbon_test.cpp b/common/fuzzing/proto_to_carbon_test.cpp new file mode 100644 index 000000000000..18227f3543ae --- /dev/null +++ b/common/fuzzing/proto_to_carbon_test.cpp @@ -0,0 +1,73 @@ +// 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 + +#include "common/fuzzing/proto_to_carbon.h" + +#include +#include + +#include "common/error.h" +#include "common/fuzzing/carbon.pb.h" + +namespace Carbon::Testing { +namespace { + +TEST(FuzzerUtilTest, ProtoToCarbon) { + const ErrorOr carbon_proto = ParseCarbonTextProto(R"( + compilation_unit { + package_statement { package_name: "P" } + is_api: true + declarations { + function { + name { + name: "Main" + } + param_pattern {} + return_term { + kind: Expression + type { int_type_literal {} } + } + body { + statements { + return_expression_statement { + expression { int_literal { value: 0 } } + } + } + } + } + } + })"); + ASSERT_TRUE(carbon_proto.ok()); + static constexpr char SourceCode[] = R"(// Generated by proto_to_carbon. +package P api; + +fn Main() -> i32 +{ +return 0; +} + +)"; + EXPECT_THAT(ProtoToCarbon(*carbon_proto, /*maybe_add_main=*/false), + testing::Eq(SourceCode)); + EXPECT_THAT(ProtoToCarbon(*carbon_proto, /*maybe_add_main=*/true), + testing::Eq(SourceCode)); +} + +TEST(FuzzerUtilTest, ParseCarbonTextProtoWithUnknownField) { + const ErrorOr carbon_proto = ParseCarbonTextProto(R"( + compilation_unit { + garbage: "value" + declarations { + choice { + name { + name: "Ch" + } + } + } + })"); + ASSERT_FALSE(carbon_proto.ok()); +} + +} // namespace +} // namespace Carbon::Testing diff --git a/explorer/fuzzing/BUILD b/explorer/fuzzing/BUILD index 8feef0cfe675..1f25225d5f99 100644 --- a/explorer/fuzzing/BUILD +++ b/explorer/fuzzing/BUILD @@ -16,21 +16,18 @@ cc_library( ], ) -cc_library( - name = "fuzzer_util", +cc_binary( + name = "ast_to_proto", testonly = 1, - srcs = ["fuzzer_util.cpp"], - hdrs = ["fuzzer_util.h"], + srcs = ["ast_to_proto_main.cpp"], deps = [ - "//common:check", + ":ast_to_proto_lib", + "//common:bazel_working_dir", "//common:error", "//common/fuzzing:carbon_cc_proto", - "//common/fuzzing:proto_to_carbon_lib", - "//explorer/interpreter:exec_program", - "//explorer/interpreter:trace_stream", + "//explorer/ast", + "//explorer/common:arena", "//explorer/syntax", - "//explorer/syntax:prelude", - "@bazel_tools//tools/cpp/runfiles", "@com_google_protobuf//:protobuf_headers", "@llvm-project//llvm:Support", ], @@ -50,35 +47,34 @@ cc_test( deps = [ ":ast_to_proto_lib", "//common/fuzzing:carbon_cc_proto", + "//common/fuzzing:proto_to_carbon_lib", "//explorer/syntax", "@com_google_googletest//:gtest", "@com_google_protobuf//:protobuf_headers", - "@llvm-project//llvm:Support", ], ) -cc_binary( - name = "fuzzverter", +cc_library( + name = "fuzzer_util", testonly = 1, - srcs = ["fuzzverter.cpp"], + srcs = ["fuzzer_util.cpp"], + hdrs = ["fuzzer_util.h"], deps = [ - ":ast_to_proto_lib", - ":fuzzer_util", + "//common:check", "//common:error", "//common/fuzzing:carbon_cc_proto", - "//explorer/common:error_builders", - "//explorer/common:nonnull", + "//common/fuzzing:proto_to_carbon_lib", + "//explorer/ast", + "//explorer/interpreter:exec_program", + "//explorer/interpreter:trace_stream", "//explorer/syntax", + "//explorer/syntax:prelude", + "@bazel_tools//tools/cpp/runfiles", "@com_google_protobuf//:protobuf_headers", "@llvm-project//llvm:Support", ], ) -filegroup( - name = "fuzzer_corpus_files", - srcs = glob(["fuzzer_corpus/**"]), -) - cc_test( name = "fuzzer_util_test", srcs = ["fuzzer_util_test.cpp"], @@ -88,50 +84,7 @@ cc_test( deps = [ ":fuzzer_util", "//common:gtest_main", - "@com_google_googletest//:gtest", - "@com_google_protobuf//:protobuf_headers", - "@llvm-project//llvm:Support", - ], -) - -cc_test( - name = "proto_to_carbon_test", - srcs = ["proto_to_carbon_test.cpp"], - args = [ - "$(locations //explorer:standard_libraries)", - "$(locations //explorer/testdata:carbon_files)", - ], - data = [ - "//explorer:standard_libraries", - "//explorer/testdata:carbon_files", - ], - deps = [ - ":ast_to_proto_lib", - "//common/fuzzing:carbon_cc_proto", "//common/fuzzing:proto_to_carbon_lib", - "//explorer/syntax", - "@com_google_googletest//:gtest", - "@com_google_protobuf//:protobuf_headers", - "@llvm-project//llvm:Support", - ], -) - -cc_test( - name = "clone_test", - srcs = ["clone_test.cpp"], - args = [ - "$(locations //explorer:standard_libraries)", - "$(locations //explorer/testdata:carbon_files)", - ], - data = [ - "//explorer:standard_libraries", - "//explorer/testdata:carbon_files", - ], - deps = [ - ":ast_to_proto_lib", - "//common/fuzzing:carbon_cc_proto", - "//explorer/ast", - "//explorer/syntax", "@com_google_googletest//:gtest", "@com_google_protobuf//:protobuf_headers", "@llvm-project//llvm:Support", diff --git a/explorer/fuzzing/README.md b/explorer/fuzzing/README.md index 9203fb7ba615..80168dc5119c 100644 --- a/explorer/fuzzing/README.md +++ b/explorer/fuzzing/README.md @@ -36,44 +36,29 @@ message definition in `common/fuzzing/carbon.proto`. ## Incorporating AST changes into the fuzzer -Fuzzer AST representation in -[carbon.proto](https://github.com/carbon-language/carbon-lang/blob/trunk/common/fuzzing/carbon.proto) -needs to be updated when changes are made to the AST, like adding a new AST node +Fuzzer AST representation in [carbon.proto](/common/fuzzing/carbon.proto) needs +to be updated when changes are made to the AST, like adding a new AST node classes or changing relevant data members of existing nodes. -There are two unit tests which normally should not require direct changes, as -both tests work off of Carbon test files in -[testdata](https://github.com/carbon-language/carbon-lang/tree/trunk/explorer/testdata). - -- [ast_to_proto_test.cpp](https://github.com/carbon-language/carbon-lang/blob/trunk/explorer/fuzzing/ast_to_proto_test.cpp) - is a 'smoke' test which verifies that each field of Carbon proto is - populated at least once after converting all of test Carbon files and - merging the results into a single protocol buffer. - -- [proto_to_carbon_test.cpp](https://github.com/carbon-language/carbon-lang/blob/trunk/explorer/fuzzing/proto_to_carbon_test.cpp) - uses a 'roundtrip' approach, by converting each parseable Carbon file to a - proto representation, then back to Carbon source, parsing this source into a - second instance of an AST, and comparing the second AST with the original - AST using `AST::Dump()` method. The goal of the test is to ensure that - `carbon.proto` is able to represent ASTs correctly without information loss. +[ast_to_proto_test](ast_to_proto_test.cpp) normally should not require direct +changes, as tests work off of Carbon test files in +[testdata](/explorer/testdata). To incorporate AST changes into fuzzing logic: 1. Add appropriate AST information to - [carbon.proto](https://github.com/carbon-language/carbon-lang/blob/trunk/common/fuzzing/carbon.proto). - Use existing similar cases as examples. + [carbon.proto](/common/fuzzing/carbon.proto). Use existing similar cases as + examples. -1. Add logic to populate the proto to - [ast_to_proto.cpp](https://github.com/carbon-language/carbon-lang/blob/trunk/explorer/fuzzing/ast_to_proto.cpp). +2. Modify [proto_to_carbon.cpp](/common/fuzzing/proto_to_carbon.cpp) which + handles printing of a Carbon proto instance as a Carbon source string. For + example, add code to print newly introduced proto fields. -1. Make sure `ast_to_proto_test` passes with the new changes. +3. Add logic to populate the proto to + [ast_to_proto.cpp](/explorer/fuzzing/ast_to_proto.cpp). -1. Modify - [proto_to_carbon.cpp](https://github.com/carbon-language/carbon-lang/blob/trunk/common/fuzzing/proto_to_carbon.cpp) - which handles printing of a Carbon proto instance as a Carbon source string. - For example, add code to print newly introduced proto fields. - -1. Make sure `proto_to_carbon_test` passes after the changes. +4. Make sure `bazel test //explorer/fuzzing:ast_to_proto_test` passes with the + new changes. ## Running the fuzzer @@ -85,36 +70,35 @@ a crash is triggered, or forever in a bug-free program ;). To run in 'unit test' mode: ```bash -bazel test --config=proto-fuzzer --test_output=all //explorer/fuzzing:explorer_fuzzer +bazel test //explorer/fuzzing:explorer_fuzzer ``` To run in 'fuzzing' mode: ```bash -bazel build --config=proto-fuzzer //explorer/fuzzing:explorer_fuzzer +bazel build --config=fuzzer //explorer/fuzzing:explorer_fuzzer.full_corpus -bazel-bin/explorer/fuzzing/explorer_fuzzer +bazel-bin/explorer/fuzzing/explorer_fuzzer.full_corpus +``` + +## Investigating a crash + +Typically it's going to be easiest to run explorer on directly. You can do this +with: + +````bash +# Convert the crash to a source file. +bazel run //common/fuzzing:proto_to_carbon -- /tmp/crash.textproto > crash.carbon + +# Run explorer on the crash. +bazel run //explorer -- crash.carbon ``` It's also possible to run the fuzzer on a single input: ```bash -bazel-bin/explorer/fuzzing/explorer_fuzzer /tmp/crash.textproto -``` - -## Investigating a crash - -To reproduce a crash, run the fuzzer on the crashing input as described above. - -A separate tool called `fuzzverter` can be used for things like converting a -crashing input to Carbon source code for running `explorer` on the code -directly. - -To convert a `Fuzzing::Carbon` text proto to Carbon source: - -```bash -bazel-bin/explorer/fuzzing/fuzzverter --mode proto_to_carbon --input /tmp/crash.textproto -``` +bazel-bin/explorer/fuzzing/explorer_fuzzer.full_corpus /tmp/crash.textproto +```` ## Generating new fuzzer corpus entries @@ -125,5 +109,5 @@ to be a `Fuzzing::Carbon` text proto. To generate a text proto from Carbon source: ```bash -bazel-bin/explorer/fuzzing/fuzzverter --mode carbon_to_proto --input /tmp/crash.carbon --output /tmp/crash.textproto +bazel run //explorer/fuzzing:ast_to_proto -- /tmp/crash.carbon > crash.textproto ``` diff --git a/explorer/fuzzing/ast_to_proto.cpp b/explorer/fuzzing/ast_to_proto.cpp index d3b864ed86cb..179388a9f25a 100644 --- a/explorer/fuzzing/ast_to_proto.cpp +++ b/explorer/fuzzing/ast_to_proto.cpp @@ -843,15 +843,15 @@ static auto DeclarationToProto(const Declaration& declaration) return declaration_proto; } -auto AstToProto(const AST& ast) -> Fuzzing::CompilationUnit { - Fuzzing::CompilationUnit compilation_unit; - *compilation_unit.mutable_package_statement() = - LibraryNameToProto(ast.package); - compilation_unit.set_is_api(ast.is_api); +auto AstToProto(const AST& ast) -> Fuzzing::Carbon { + Fuzzing::Carbon carbon; + auto* unit = carbon.mutable_compilation_unit(); + *unit->mutable_package_statement() = LibraryNameToProto(ast.package); + unit->set_is_api(ast.is_api); for (const Declaration* declaration : ast.declarations) { - *compilation_unit.add_declarations() = DeclarationToProto(*declaration); + *unit->add_declarations() = DeclarationToProto(*declaration); } - return compilation_unit; + return carbon; } } // namespace Carbon diff --git a/explorer/fuzzing/ast_to_proto.h b/explorer/fuzzing/ast_to_proto.h index 7f9810533b38..a7660595b238 100644 --- a/explorer/fuzzing/ast_to_proto.h +++ b/explorer/fuzzing/ast_to_proto.h @@ -11,7 +11,7 @@ namespace Carbon { // Builds a protobuf representation of `ast`. -auto AstToProto(const AST& ast) -> Fuzzing::CompilationUnit; +auto AstToProto(const AST& ast) -> Fuzzing::Carbon; } // namespace Carbon diff --git a/explorer/fuzzing/ast_to_proto_main.cpp b/explorer/fuzzing/ast_to_proto_main.cpp new file mode 100644 index 000000000000..c8812e77c438 --- /dev/null +++ b/explorer/fuzzing/ast_to_proto_main.cpp @@ -0,0 +1,66 @@ +// 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 + +// To convert a Carbon file to a text proto: +// `ast_to_proto ` + +#include + +#include +#include +#include + +#include "common/bazel_working_dir.h" +#include "common/error.h" +#include "common/fuzzing/carbon.pb.h" +#include "explorer/ast/ast.h" +#include "explorer/common/arena.h" +#include "explorer/fuzzing/ast_to_proto.h" +#include "explorer/syntax/parse.h" + +namespace Carbon { + +auto Main(int argc, char** argv) -> ErrorOr { + Carbon::SetWorkingDirForBazel(); + + if (argc != 2) { + return Error("Syntax: ast_to_proto "); + } + if (!std::filesystem::is_regular_file(argv[1])) { + return Error("Argument must be a file."); + } + + // Read the input file. + std::ifstream proto_file(argv[1]); + std::stringstream buffer; + buffer << proto_file.rdbuf(); + proto_file.close(); + + Arena arena; + const ErrorOr ast = Parse(&arena, argv[1], + /*parser_debug=*/false); + if (!ast.ok()) { + return ErrorBuilder() << "Parsing failed: " << ast.error().message(); + } + Fuzzing::Carbon carbon_proto = AstToProto(*ast); + + std::string proto_string; + google::protobuf::TextFormat::Printer p; + if (!p.PrintToString(carbon_proto, &proto_string)) { + return Error("Failed to convert to text proto"); + } + std::cout << proto_string; + return Success(); +} + +} // namespace Carbon + +auto main(int argc, char** argv) -> int { + auto err = Carbon::Main(argc, argv); + if (!err.ok()) { + std::cerr << err.error().message() << "\n"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/explorer/fuzzing/ast_to_proto_test.cpp b/explorer/fuzzing/ast_to_proto_test.cpp index e7994358df2d..80fa17f097df 100644 --- a/explorer/fuzzing/ast_to_proto_test.cpp +++ b/explorer/fuzzing/ast_to_proto_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -13,8 +14,8 @@ #include #include +#include "common/fuzzing/proto_to_carbon.h" #include "explorer/syntax/parse.h" -#include "llvm/Support/Error.h" namespace Carbon::Testing { namespace { @@ -26,6 +27,18 @@ using ::google::protobuf::Reflection; static std::vector* carbon_files = nullptr; +// Returns a string representation of `ast`. +auto AstToString(const AST& ast) -> std::string { + std::string s; + llvm::raw_string_ostream out(s); + out << "package " << ast.package.package << (ast.is_api ? "api" : "impl") + << ";\n"; + for (auto* declaration : ast.declarations) { + out << *declaration << "\n"; + } + return s; +} + // Concatenates message and field names. auto FieldName(const Descriptor& descriptor, const FieldDescriptor& field) -> std::string { @@ -80,35 +93,29 @@ auto CollectUsedFields(const Message& message, } } -// Determines which fields in the proto have not been used at all. -auto GetUnusedFields(const Message& message) -> std::set { - std::set all_messages; - std::set all_fields; - CollectAllFields(*message.GetDescriptor(), all_messages, all_fields); - - std::set used_fields; - CollectUsedFields(message, used_fields); - - std::set unused_fields; - std::set_difference(all_fields.begin(), all_fields.end(), used_fields.begin(), - used_fields.end(), - std::inserter(unused_fields, unused_fields.begin())); - return unused_fields; -} - // A 'smoke' test to check that each field present in `carbon.proto` is set at // least once after converting all Carbon test sources to proto representation. TEST(AstToProtoTest, SetsAllProtoFields) { - Carbon::Fuzzing::CompilationUnit merged_proto; + Fuzzing::Carbon merged_proto; for (const llvm::StringRef f : *carbon_files) { - Carbon::Arena arena; - const ErrorOr ast = Carbon::Parse(&arena, f, /*parser_debug=*/false); + Arena arena; + const ErrorOr ast = Parse(&arena, f, /*parser_debug=*/false); if (ast.ok()) { merged_proto.MergeFrom(AstToProto(*ast)); } } - std::set unused_fields = GetUnusedFields(merged_proto); + std::set all_messages; + std::set all_fields; + CollectAllFields(*Fuzzing::Carbon::GetDescriptor(), all_messages, all_fields); + + std::set used_fields; + CollectUsedFields(merged_proto, used_fields); + + std::set unused_fields; + std::set_difference(all_fields.begin(), all_fields.end(), used_fields.begin(), + used_fields.end(), + std::inserter(unused_fields, unused_fields.begin())); EXPECT_EQ(unused_fields.size(), 0) << "Unused fields" << std::accumulate(unused_fields.begin(), unused_fields.end(), @@ -118,6 +125,74 @@ TEST(AstToProtoTest, SetsAllProtoFields) { }); } +// Ensures that `carbon.proto` is able to represent ASTs correctly without +// information loss by doing round-trip testing of files: +// +// 1) Converts each parseable Carbon file to a proto representation. +// 2) Converts back to Carbon source. +// 3) Parses the source into a second instance of an AST. +// 4) Compares the second AST with the original. +TEST(AstToProtoTest, Roundtrip) { + int parsed_ok_count = 0; + for (const llvm::StringRef f : *carbon_files) { + Arena arena; + const ErrorOr ast = Parse(&arena, f, /*parser_debug=*/false); + if (ast.ok()) { + ++parsed_ok_count; + const std::string source_from_proto = + ProtoToCarbon(AstToProto(*ast), /*maybe_add_main=*/false); + SCOPED_TRACE(testing::Message() + << "Carbon file: " << f << ", source from proto:\n" + << source_from_proto); + const ErrorOr ast_from_proto = + ParseFromString(&arena, f, source_from_proto, /*parser_debug=*/false); + + if (ast_from_proto.ok()) { + EXPECT_EQ(AstToString(*ast), AstToString(*ast_from_proto)); + } else { + ADD_FAILURE() << "Parse error " << ast_from_proto.error().message(); + } + } + } + // Makes sure files were actually processed. + EXPECT_GT(parsed_ok_count, 0); +} + +auto CloneAST(Arena& arena, const AST& ast) -> AST { + CloneContext context(&arena); + return { + .package = ast.package, + .is_api = ast.is_api, + .imports = ast.imports, + .declarations = context.Clone(ast.declarations), + .main_call = context.Clone(ast.main_call), + .num_prelude_declarations = ast.num_prelude_declarations, + }; +} + +// Verifies that an AST and its clone produce identical protos. +TEST(AstToProtoTest, SameProtoAfterClone) { + int parsed_ok_count = 0; + for (const llvm::StringRef f : *carbon_files) { + Arena arena; + const ErrorOr ast = Parse(&arena, f, /*parser_debug=*/false); + if (ast.ok()) { + ++parsed_ok_count; + const AST clone = CloneAST(arena, *ast); + const Fuzzing::Carbon orig_proto = AstToProto(*ast); + const Fuzzing::Carbon clone_proto = AstToProto(clone); + // TODO: Use EqualsProto once it's available. + EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( + orig_proto, clone_proto)) + << "clone produced a different AST. original:\n" + << AstToString(*ast) << "clone:\n" + << AstToString(clone); + } + } + // Makes sure files were actually processed. + EXPECT_GT(parsed_ok_count, 0); +} + } // namespace } // namespace Carbon::Testing diff --git a/explorer/fuzzing/clone_test.cpp b/explorer/fuzzing/clone_test.cpp deleted file mode 100644 index c4da163dfb73..000000000000 --- a/explorer/fuzzing/clone_test.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// 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 - -#include -#include -#include - -#include "explorer/ast/clone_context.h" -#include "explorer/fuzzing/ast_to_proto.h" -#include "explorer/syntax/parse.h" - -namespace Carbon::Testing { -namespace { - -static std::vector* carbon_files = nullptr; - -auto CloneAST(Arena& arena, const AST& ast) -> AST { - CloneContext context(&arena); - return { - .package = ast.package, - .is_api = ast.is_api, - .imports = ast.imports, - .declarations = context.Clone(ast.declarations), - .main_call = context.Clone(ast.main_call), - .num_prelude_declarations = ast.num_prelude_declarations, - }; -} - -// Returns a string representation of `ast`. -auto AstToString(const AST& ast) -> std::string { - std::string s; - llvm::raw_string_ostream out(s); - out << "package " << ast.package.package << (ast.is_api ? "api" : "impl") - << ";\n"; - for (auto* declaration : ast.declarations) { - out << *declaration << "\n"; - } - return s; -} - -TEST(CloneTest, SameProtoAfterClone) { - int parsed_ok_count = 0; - for (const llvm::StringRef f : *carbon_files) { - Carbon::Arena arena; - const ErrorOr ast = Carbon::Parse(&arena, f, /*parser_debug=*/false); - if (ast.ok()) { - ++parsed_ok_count; - const AST clone = CloneAST(arena, *ast); - const Fuzzing::CompilationUnit orig_proto = AstToProto(*ast); - const Fuzzing::CompilationUnit clone_proto = AstToProto(clone); - // TODO: Use EqualsProto once it's available. - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - orig_proto, clone_proto)) - << "clone produced a different AST. original:\n" - << AstToString(*ast) << "clone:\n" - << AstToString(clone); - } - } - // Makes sure files were actually processed. - EXPECT_GT(parsed_ok_count, 0); -} - -} // namespace -} // namespace Carbon::Testing - -auto main(int argc, char** argv) -> int { - ::testing::InitGoogleTest(&argc, argv); - // gtest should remove flags, leaving just input files. - std::vector carbon_files(&argv[1], &argv[argc]); - Carbon::Testing::carbon_files = &carbon_files; - return RUN_ALL_TESTS(); -} diff --git a/explorer/fuzzing/explorer_fuzzer.cpp b/explorer/fuzzing/explorer_fuzzer.cpp index 9fe8638e46c3..55721951f51e 100644 --- a/explorer/fuzzing/explorer_fuzzer.cpp +++ b/explorer/fuzzing/explorer_fuzzer.cpp @@ -10,5 +10,5 @@ DEFINE_TEXT_PROTO_FUZZER(const Carbon::Fuzzing::Carbon& input) { // Only verifying it doesn't crash. - (void)Carbon::ParseAndExecute(input.compilation_unit()); + (void)Carbon::ParseAndExecute(input); } diff --git a/explorer/fuzzing/fuzzer_util.cpp b/explorer/fuzzing/fuzzer_util.cpp index b88f564c45cf..ac84bda253a7 100644 --- a/explorer/fuzzing/fuzzer_util.cpp +++ b/explorer/fuzzing/fuzzer_util.cpp @@ -19,16 +19,7 @@ namespace Carbon { -// Appended to fuzzer-generated Carbon source when the source is missing -// `Main()` definition, to prevent early error return in semantic analysis. -static constexpr char EmptyMain[] = R"( -fn Main() -> i32 { - return 0; -} -)"; - -auto Internal::GetRunfilesFile(const std::string& file) - -> ErrorOr { +auto GetRunfilesFile(const std::string& file) -> ErrorOr { using bazel::tools::cpp::runfiles::Runfiles; std::string error; // `Runfiles::Create()` fails if passed an empty `argv0`. @@ -44,42 +35,15 @@ auto Internal::GetRunfilesFile(const std::string& file) return full_path; } -auto ParseCarbonTextProto(const std::string& contents, bool allow_unknown) - -> ErrorOr { - google::protobuf::TextFormat::Parser parser; - if (allow_unknown) { - parser.AllowUnknownField(true); - parser.AllowUnknownExtension(true); - } - Fuzzing::Carbon carbon_proto; - if (!parser.ParseFromString(contents, &carbon_proto)) { - return ErrorBuilder() << "Couldn't parse Carbon text proto"; - } - return carbon_proto; -} - -auto ProtoToCarbonWithMain(const Fuzzing::CompilationUnit& compilation_unit) - -> std::string { - const bool has_main = std::any_of( - compilation_unit.declarations().begin(), - compilation_unit.declarations().end(), - [](const Fuzzing::Declaration& decl) { - return decl.kind_case() == Fuzzing::Declaration::kFunction && - decl.function().name().name() == "Main"; - }); - return Carbon::ProtoToCarbon(compilation_unit) + (has_main ? "" : EmptyMain); -} - -auto ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit) - -> ErrorOr { - const std::string source = ProtoToCarbonWithMain(compilation_unit); +auto ParseAndExecute(const Fuzzing::Carbon& carbon) -> ErrorOr { + const std::string source = ProtoToCarbon(carbon, /*maybe_add_main=*/true); Arena arena; CARBON_ASSIGN_OR_RETURN(AST ast, ParseFromString(&arena, "Fuzzer.carbon", source, /*parser_debug=*/false)); const ErrorOr prelude_path = - Internal::GetRunfilesFile("carbon/explorer/data/prelude.carbon"); + GetRunfilesFile("carbon/explorer/data/prelude.carbon"); // Can't do anything without a prelude, so it's a fatal error. CARBON_CHECK(prelude_path.ok()) << prelude_path.error(); diff --git a/explorer/fuzzing/fuzzer_util.h b/explorer/fuzzing/fuzzer_util.h index 235ad699b4c0..d584adf3b180 100644 --- a/explorer/fuzzing/fuzzer_util.h +++ b/explorer/fuzzing/fuzzer_util.h @@ -7,31 +7,18 @@ #include "common/error.h" #include "common/fuzzing/carbon.pb.h" +#include "explorer/ast/ast.h" namespace Carbon { -// Parses text proto with a Carbon message, optionally ignoring unknown fields. -auto ParseCarbonTextProto(const std::string& contents, - bool allow_unknown = true) - -> ErrorOr; - -// Converts `compilation_unit` to Carbon. Adds an default `Main()` -// definition if one is not present in the proto. -auto ProtoToCarbonWithMain(const Fuzzing::CompilationUnit& compilation_unit) - -> std::string; - // Parses and executes a fuzzer-generated program. // Returns program result if execution was successful. -auto ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit) - -> ErrorOr; - -namespace Internal { +auto ParseAndExecute(const Fuzzing::Carbon& carbon) -> ErrorOr; // 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 // CARBON_EXPLORER_FUZZING_FUZZER_UTIL_H_ diff --git a/explorer/fuzzing/fuzzer_util_test.cpp b/explorer/fuzzing/fuzzer_util_test.cpp index 8ce7d179b388..69c3fd6eee07 100644 --- a/explorer/fuzzing/fuzzer_util_test.cpp +++ b/explorer/fuzzing/fuzzer_util_test.cpp @@ -9,6 +9,7 @@ #include +#include "common/fuzzing/proto_to_carbon.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" @@ -41,38 +42,17 @@ TEST(FuzzerUtilTest, ParseAndExecute) { } })"); ASSERT_TRUE(carbon_proto.ok()); - const ErrorOr result = ParseAndExecute(carbon_proto->compilation_unit()); + const ErrorOr result = ParseAndExecute(*carbon_proto); ASSERT_TRUE(result.ok()) << "Execution failed: " << result.error(); EXPECT_EQ(*result, 0); } TEST(FuzzerUtilTest, GetRunfilesFile) { - EXPECT_THAT(*Internal::GetRunfilesFile("carbon/explorer/data/prelude.carbon"), + EXPECT_THAT(*GetRunfilesFile("carbon/explorer/data/prelude.carbon"), testing::EndsWith("/prelude.carbon")); - EXPECT_THAT(Internal::GetRunfilesFile("nonexistent-file").error().message(), + EXPECT_THAT(GetRunfilesFile("nonexistent-file").error().message(), testing::EndsWith("doesn't exist")); } -TEST(FuzzerUtilTest, ParseCarbonTextProtoWithUnknownField) { - const ErrorOr carbon_proto = - ParseCarbonTextProto(R"( - compilation_unit { - garbage: "value" - declarations { - choice { - name { - name: "Ch" - } - } - } - })", - /*allow_unknown=*/true); - ASSERT_TRUE(carbon_proto.ok()); - // No EqualsProto in gmock - https://github.com/google/googletest/issues/1761. - EXPECT_EQ( - carbon_proto->compilation_unit().declarations(0).choice().name().name(), - "Ch"); -} - } // namespace } // namespace Carbon::Testing diff --git a/explorer/fuzzing/fuzzverter.cpp b/explorer/fuzzing/fuzzverter.cpp deleted file mode 100644 index 38d318316f4c..000000000000 --- a/explorer/fuzzing/fuzzverter.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// 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 - -// An utility for converting between fuzzer protos and Carbon sources. -// -// For example, to convert a crashing input in text proto to carbon source: -// `fuzzverter --mode=proto_to_carbon --input file.textproto` -// -// To generate a new text proto from carbon source for seeding the corpus: -// `fuzzverter --mode=carbon_to_proto --input file.carbon` - -#include - -#include -#include -#include -#include - -#include "common/error.h" -#include "common/fuzzing/carbon.pb.h" -#include "explorer/common/error_builders.h" -#include "explorer/fuzzing/ast_to_proto.h" -#include "explorer/fuzzing/fuzzer_util.h" -#include "explorer/syntax/parse.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/InitLLVM.h" - -namespace Carbon { - -namespace cl = llvm::cl; - -// Reads a file and returns its contents as a string. -static auto ReadFile(std::string_view file_name) -> ErrorOr { - std::ifstream file(file_name, std::ios::in); - if (!file.is_open()) { - return ErrorBuilder() << "Could not open " << file_name << " for reading"; - } - std::stringstream ss; - ss << file.rdbuf(); - return ss.str(); -} - -// Writes string `s` to `file_name`. -static auto WriteFile(std::string_view s, std::string_view file_name) - -> ErrorOr { - std::ofstream file(file_name, std::ios::out); - if (!file.is_open()) { - return ErrorBuilder() << "Could not open " << file_name << " for writing"; - } - file << s; - return Success(); -} - -// Converts text proto to Carbon source. -static auto TextProtoToCarbon(std::string_view input_file_name, - std::string_view output_file_name) - -> ErrorOr { - CARBON_ASSIGN_OR_RETURN(const std::string input_contents, - ReadFile(input_file_name)); - CARBON_ASSIGN_OR_RETURN(const Fuzzing::Carbon carbon_proto, - ParseCarbonTextProto(input_contents)); - const std::string carbon_source = - ProtoToCarbonWithMain(carbon_proto.compilation_unit()); - return WriteFile(carbon_source, output_file_name); -} - -// Converts Carbon source to text proto. -static auto CarbonToTextProto(std::string_view input_file_name, - std::string_view output_file_name) - -> ErrorOr { - Carbon::Arena arena; - const ErrorOr ast = Carbon::Parse(&arena, input_file_name, - /*parser_debug=*/false); - if (!ast.ok()) { - return ErrorBuilder() << "Parsing failed: " << ast.error().message(); - } - Fuzzing::Carbon carbon_proto; - *carbon_proto.mutable_compilation_unit() = AstToProto(*ast); - - std::string proto_string; - google::protobuf::TextFormat::Printer p; - if (!p.PrintToString(carbon_proto, &proto_string)) { - return Error("Failed to convert to text proto"); - } - return WriteFile(proto_string, output_file_name); -} - -// Command line options for defining input/output format. -enum class ConversionMode { TextProtoToCarbon, CarbonToTextProto }; - -auto Main(int argc, char* argv[]) -> ErrorOr { - llvm::InitLLVM init_llvm(argc, argv); - - cl::opt mode( - "mode", cl::desc("Conversion mode"), - cl::values( - clEnumValN(ConversionMode::TextProtoToCarbon, "proto_to_carbon", - "Convert text proto to Carbon source"), - clEnumValN(ConversionMode::CarbonToTextProto, "carbon_to_proto", - "Convert Carbon source to text proto")), - cl::Required); - cl::opt input_file_name("input", cl::desc(""), - cl::init("/dev/stdin")); - cl::opt output_file_name("output", cl::desc(""), - cl::init("/dev/stdout")); - cl::ParseCommandLineOptions(argc, argv); - - switch (mode) { - case ConversionMode::TextProtoToCarbon: - return TextProtoToCarbon(input_file_name, output_file_name); - case ConversionMode::CarbonToTextProto: - return CarbonToTextProto(input_file_name, output_file_name); - } -} - -} // namespace Carbon - -auto main(int argc, char* argv[]) -> int { - if (const auto result = Carbon::Main(argc, argv); !result.ok()) { - llvm::errs() << result.error().message() << "\n"; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} diff --git a/explorer/fuzzing/proto_to_carbon_test.cpp b/explorer/fuzzing/proto_to_carbon_test.cpp deleted file mode 100644 index 1ae05fe39e2e..000000000000 --- a/explorer/fuzzing/proto_to_carbon_test.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// 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 - -#include "common/fuzzing/proto_to_carbon.h" - -#include -#include - -#include "explorer/fuzzing/ast_to_proto.h" -#include "explorer/syntax/parse.h" - -namespace Carbon::Testing { -namespace { - -static std::vector* carbon_files = nullptr; - -// Returns a string representation of `ast`. -auto AstToString(const AST& ast) -> std::string { - std::string s; - llvm::raw_string_ostream out(s); - out << "package " << ast.package.package << (ast.is_api ? "api" : "impl") - << ";\n"; - for (auto* declaration : ast.declarations) { - out << *declaration << "\n"; - } - return s; -} - -TEST(ProtoToCarbonTest, Roundtrip) { - int parsed_ok_count = 0; - for (const llvm::StringRef f : *carbon_files) { - Carbon::Arena arena; - const ErrorOr ast = Carbon::Parse(&arena, f, /*parser_debug=*/false); - if (ast.ok()) { - ++parsed_ok_count; - const std::string source_from_proto = ProtoToCarbon(AstToProto(*ast)); - SCOPED_TRACE(testing::Message() - << "Carbon file: " << f << ", source from proto:\n" - << source_from_proto); - const ErrorOr ast_from_proto = Carbon::ParseFromString( - &arena, f, source_from_proto, /*parser_debug=*/false); - - if (ast_from_proto.ok()) { - EXPECT_EQ(AstToString(*ast), AstToString(*ast_from_proto)); - } else { - ADD_FAILURE() << "Parse error " << ast_from_proto.error().message(); - } - } - } - // Makes sure files were actually processed. - EXPECT_GT(parsed_ok_count, 0); -} - -} // namespace -} // namespace Carbon::Testing - -auto main(int argc, char** argv) -> int { - ::testing::InitGoogleTest(&argc, argv); - // gtest should remove flags, leaving just input files. - std::vector carbon_files(&argv[1], &argv[argc]); - Carbon::Testing::carbon_files = &carbon_files; - return RUN_ALL_TESTS(); -} diff --git a/explorer/fuzzing/regen_corpus.py b/explorer/fuzzing/regen_corpus.py index f5a322715939..40a627a43ac0 100755 --- a/explorer/fuzzing/regen_corpus.py +++ b/explorer/fuzzing/regen_corpus.py @@ -35,8 +35,7 @@ def _carbon_to_proto(carbon_file: str) -> str: """Converts carbon file to text proto string.""" try: p = subprocess.run( - "bazel-bin/explorer/fuzzing/fuzzverter --mode carbon_to_proto " - f"--input {carbon_file} --output /dev/stdout", + f"bazel-bin/explorer/fuzzing/ast_to_proto {carbon_file}", shell=True, check=True, stdout=subprocess.PIPE, @@ -65,12 +64,12 @@ def _write_corpus_files(text_protos: Iterable[str], corpus_dir: str) -> None: def main() -> None: os.chdir(os.path.join(os.path.dirname(__file__), "../..")) - print("Building fuzzverter...", flush=True) + print("Building ast_to_proto...", flush=True) subprocess.check_call( [ "bazel", "build", - "//explorer/fuzzing:fuzzverter", + "//explorer/fuzzing:ast_to_proto", ] ) carbon_sources = _get_files(_TESTDATA, ".carbon") @@ -95,12 +94,8 @@ def main() -> None: [ "bazel", "build", - "--features=fuzzer", - # Workaround for #1208. - "--copt=-U_LIBCPP_DEBUG", - # Workaround for #1173. - "--per_file_copt=llvm/.*@-fno-sanitize=fuzzer", - "//explorer/fuzzing:explorer_fuzzer", + "--config=fuzzer", + "//explorer/fuzzing:explorer_fuzzer.full_corpus", ] ) @@ -110,7 +105,7 @@ def main() -> None: ) subprocess.check_call( [ - "bazel-bin/explorer/fuzzing/explorer_fuzzer", + "bazel-bin/explorer/fuzzing/explorer_fuzzer.full_corpus", "-merge=1", _FUZZER_CORPUS, new_corpus_dir,