Przeglądaj źródła

Allow unknown fields in fuzzing text proto (#1296)

This is to help with frequent build breakages cased by proto changes.
Fuzzer corpus can be periodically auto-regenerated.
Crashing samples from the fuzzer are better 'preserved' in the form of fail_xx.carbon tests.
pk19604014 3 lat temu
rodzic
commit
ed93d95fce

+ 16 - 0
explorer/fuzzing/fuzzer_util.cpp

@@ -4,6 +4,8 @@
 
 #include "explorer/fuzzing/fuzzer_util.h"
 
+#include <google/protobuf/text_format.h>
+
 #include "common/check.h"
 #include "common/fuzzing/proto_to_carbon.h"
 #include "explorer/interpreter/exec_program.h"
@@ -41,6 +43,20 @@ auto Internal::GetRunfilesFile(const std::string& file)
   return full_path;
 }
 
+auto ParseCarbonTextProto(const std::string& contents, bool allow_unknown)
+    -> ErrorOr<Fuzzing::Carbon> {
+  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(

+ 5 - 0
explorer/fuzzing/fuzzer_util.h

@@ -10,6 +10,11 @@
 
 namespace Carbon {
 
+// Parses text proto with a Carbon message, optionally ignoring unknown fields.
+auto ParseCarbonTextProto(const std::string& contents,
+                          bool allow_unknown = true)
+    -> ErrorOr<Fuzzing::Carbon>;
+
 // 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)

+ 22 - 6
explorer/fuzzing/fuzzer_util_test.cpp

@@ -5,7 +5,6 @@
 #include "explorer/fuzzing/fuzzer_util.h"
 
 #include <gmock/gmock.h>
-#include <google/protobuf/text_format.h>
 #include <gtest/gtest.h>
 
 #include <fstream>
@@ -27,11 +26,10 @@ TEST(FuzzerUtilTest, RunFuzzerOnCorpus) {
     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))
-        << " couldn't parse text proto in " << f;
-    ParseAndExecute(carbon_proto.compilation_unit());
+    const ErrorOr<Fuzzing::Carbon> carbon_proto =
+        ParseCarbonTextProto(contents.str());
+    ASSERT_TRUE(carbon_proto.ok()) << "couldn't parse text proto in " << f;
+    ParseAndExecute(carbon_proto->compilation_unit());
     ++file_count;
   }
   EXPECT_GT(file_count, 0);
@@ -45,6 +43,24 @@ TEST(FuzzerUtilTest, GetRunfilesFile) {
               testing::EndsWith("doesn't exist"));
 }
 
+TEST(FuzzerUtilTest, ParseCarbonTextProtoWithUnknownField) {
+  const ErrorOr<Fuzzing::Carbon> carbon_proto =
+      ParseCarbonTextProto(R"(
+    compilation_unit {
+      garbage: "value"
+      declarations {
+        choice {
+          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(),
+            "Ch");
+}
+
 }  // namespace
 }  // namespace Carbon::Testing
 

+ 2 - 5
explorer/fuzzing/fuzzverter.cpp

@@ -58,11 +58,8 @@ static auto TextProtoToCarbon(std::string_view input_file_name,
     -> ErrorOr<Success> {
   CARBON_ASSIGN_OR_RETURN(const std::string input_contents,
                           ReadFile(input_file_name));
-  Fuzzing::Carbon carbon_proto;
-  if (!google::protobuf::TextFormat::ParseFromString(input_contents,
-                                                     &carbon_proto)) {
-    return Error("Could not parse text proto");
-  }
+  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);