diff --git a/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 b/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/executable_semantics/fuzzing/BUILD b/executable_semantics/fuzzing/BUILD index a4996b86d81a..dd249ef868b1 100644 --- a/executable_semantics/fuzzing/BUILD +++ b/executable_semantics/fuzzing/BUILD @@ -27,6 +27,10 @@ cc_library( "//common:check", "//common/fuzzing:carbon_cc_proto", "//common/fuzzing:proto_to_carbon_lib", + "//executable_semantics/interpreter:exec_program", + "//executable_semantics/syntax", + "//executable_semantics/syntax:prelude", + "@com_google_protobuf//:protobuf_headers", "@llvm-project//llvm:Support", ], ) @@ -69,6 +73,27 @@ cc_binary( ], ) +filegroup( + name = "fuzzer_corpus_files", + srcs = glob(["fuzzer_corpus/**"]), +) + +cc_test( + name = "fuzzer_util_test", + srcs = ["fuzzer_util_test.cpp"], + args = [ + "$(locations fuzzer_corpus_files)", + ], + data = [ + ":fuzzer_corpus_files", + ], + deps = [ + ":fuzzer_util", + "@com_google_googletest//:gtest", + "@llvm-project//llvm:Support", + ], +) + cc_test( name = "proto_to_carbon_test", srcs = ["proto_to_carbon_test.cpp"], @@ -91,21 +116,15 @@ cc_test( ], ) -# Needs `--config=proto-fuzzer` for `bazel build` / `bazel test`. -cc_fuzz_test( +# Needs `--config=proto-fuzzer` for `bazel build`. +cc_binary( name = "executable_semantics_fuzzer", - size = "small", + testonly = 1, srcs = ["executable_semantics_fuzzer.cpp"], - corpus = glob(["fuzzer_corpus/**"]), - tags = ["manual"], + features = ["fuzzer"], deps = [ ":fuzzer_util", - "//common/fuzzing:carbon_cc_proto", - "//executable_semantics/interpreter:exec_program", - "//executable_semantics/syntax", - "//executable_semantics/syntax:prelude", "@com_google_libprotobuf_mutator//:libprotobuf_mutator", - "@com_google_protobuf//:protobuf_headers", "@llvm-project//llvm:Support", ], ) diff --git a/executable_semantics/fuzzing/executable_semantics_fuzzer.cpp b/executable_semantics/fuzzing/executable_semantics_fuzzer.cpp index 590197ec7dc4..ec6e7aed29bf 100644 --- a/executable_semantics/fuzzing/executable_semantics_fuzzer.cpp +++ b/executable_semantics/fuzzing/executable_semantics_fuzzer.cpp @@ -2,41 +2,9 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include #include -#include "common/fuzzing/carbon.pb.h" #include "executable_semantics/fuzzing/fuzzer_util.h" -#include "executable_semantics/interpreter/exec_program.h" -#include "executable_semantics/syntax/parse.h" -#include "executable_semantics/syntax/prelude.h" -#include "llvm/Support/raw_ostream.h" - -namespace Carbon { - -// Parses and executes a fuzzer-generated program. -void ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit) { - const std::string source = ProtoToCarbonWithMain(compilation_unit); - - Arena arena; - ErrorOr ast = ParseFromString(&arena, "Fuzzer.carbon", source, - /*parser_debug=*/false); - if (!ast.ok()) { - llvm::errs() << "Parsing failed: " << ast.error().message() << "\n"; - return; - } - AddPrelude("executable_semantics/data/prelude.carbon", &arena, - &ast->declarations); - const ErrorOr result = - ExecProgram(&arena, *ast, /*trace_stream=*/std::nullopt); - if (!result.ok()) { - llvm::errs() << "Execution failed: " << result.error().message() << "\n"; - return; - } - llvm::outs() << "Executed OK: " << *result << "\n"; -} - -} // namespace Carbon DEFINE_TEXT_PROTO_FUZZER(const Carbon::Fuzzing::Carbon& input) { Carbon::ParseAndExecute(input.compilation_unit()); diff --git a/executable_semantics/fuzzing/fuzzer_util.cpp b/executable_semantics/fuzzing/fuzzer_util.cpp index 0b832716dfc5..274ab92c3468 100644 --- a/executable_semantics/fuzzing/fuzzer_util.cpp +++ b/executable_semantics/fuzzing/fuzzer_util.cpp @@ -6,6 +6,10 @@ #include "common/check.h" #include "common/fuzzing/proto_to_carbon.h" +#include "executable_semantics/interpreter/exec_program.h" +#include "executable_semantics/syntax/parse.h" +#include "executable_semantics/syntax/prelude.h" +#include "llvm/Support/raw_ostream.h" namespace Carbon { @@ -29,4 +33,25 @@ auto ProtoToCarbonWithMain(const Fuzzing::CompilationUnit& compilation_unit) return Carbon::ProtoToCarbon(compilation_unit) + (has_main ? "" : EmptyMain); } +void ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit) { + const std::string source = ProtoToCarbonWithMain(compilation_unit); + + Arena arena; + ErrorOr ast = ParseFromString(&arena, "Fuzzer.carbon", source, + /*parser_debug=*/false); + if (!ast.ok()) { + llvm::errs() << "Parsing failed: " << ast.error().message() << "\n"; + return; + } + AddPrelude("executable_semantics/data/prelude.carbon", &arena, + &ast->declarations); + const ErrorOr result = + ExecProgram(&arena, *ast, /*trace_stream=*/std::nullopt); + if (!result.ok()) { + llvm::errs() << "Execution failed: " << result.error().message() << "\n"; + return; + } + llvm::outs() << "Executed OK: " << *result << "\n"; +} + } // namespace Carbon diff --git a/executable_semantics/fuzzing/fuzzer_util.h b/executable_semantics/fuzzing/fuzzer_util.h index 931f9f07e9ec..a6071489f819 100644 --- a/executable_semantics/fuzzing/fuzzer_util.h +++ b/executable_semantics/fuzzing/fuzzer_util.h @@ -14,6 +14,9 @@ namespace Carbon { auto ProtoToCarbonWithMain(const Fuzzing::CompilationUnit& compilation_unit) -> std::string; +// Parses and executes a fuzzer-generated program. +void ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit); + } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_FUZZING_FUZZER_UTIL_H_ diff --git a/executable_semantics/fuzzing/fuzzer_util_test.cpp b/executable_semantics/fuzzing/fuzzer_util_test.cpp new file mode 100644 index 000000000000..1b03e114068a --- /dev/null +++ b/executable_semantics/fuzzing/fuzzer_util_test.cpp @@ -0,0 +1,47 @@ +// 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 "executable_semantics/fuzzing/fuzzer_util.h" + +#include +#include +#include + +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +namespace Carbon::Testing { +namespace { + +static std::vector* carbon_files = nullptr; + +// A workaround for https://github.com/carbon-language/carbon-lang/issues/1208. +TEST(FuzzerUtilTest, RunFuzzerOnCorpus) { + int file_count = 0; + for (const llvm::StringRef f : *carbon_files) { + llvm::outs() << "Processing " << f << "\n"; + std::ifstream file(f.str(), std::ios::in); + ASSERT_TRUE(file.is_open()); + std::stringstream contents; + contents << file.rdbuf(); + Fuzzing::Carbon carbon_proto; + ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(contents.str(), + &carbon_proto)); + ParseAndExecute(carbon_proto.compilation_unit()); + ++file_count; + } + EXPECT_GT(file_count, 0); +} + +} // namespace +} // namespace Carbon::Testing + +auto main(int argc, char** argv) -> int { + ::testing::InitGoogleTest(&argc, argv); + Carbon::Testing::carbon_files = + new std::vector(&argv[1], &argv[argc]); + return RUN_ALL_TESTS(); +}