• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2016 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include <dirent.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <algorithm>
26 #include <string>
27 #include <vector>
28 
29 #include "absl/flags/flag.h"
30 #include "absl/types/optional.h"
31 #include "gtest/gtest.h"
32 
33 #include <grpc/slice.h>
34 #include <grpc/support/alloc.h>
35 #include <grpc/support/log.h>
36 
37 #include "src/core/lib/gprpp/env.h"
38 #include "src/core/lib/iomgr/error.h"
39 #include "test/core/util/test_config.h"
40 #include "test/core/util/tls_utils.h"
41 #include "test/cpp/util/test_config.h"
42 
43 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
44 extern bool squelch;
45 
46 ABSL_FLAG(std::string, file, "", "Use this file as test data");
47 ABSL_FLAG(std::string, directory, "", "Use this directory as test data");
48 
49 class FuzzerCorpusTest : public ::testing::TestWithParam<std::string> {};
50 
TEST_P(FuzzerCorpusTest,RunOneExample)51 TEST_P(FuzzerCorpusTest, RunOneExample) {
52   // Need to call grpc_init() here to use a slice, but need to shut it
53   // down before calling LLVMFuzzerTestOneInput(), because most
54   // implementations of that function will initialize and shutdown gRPC
55   // internally.
56   fprintf(stderr, "Example file: %s\n", GetParam().c_str());
57   squelch = false;
58   std::string buffer = grpc_core::testing::GetFileContents(GetParam());
59   size_t length = buffer.size();
60   void* data = gpr_malloc(length);
61   if (length > 0) {
62     memcpy(data, buffer.data(), length);
63   }
64   LLVMFuzzerTestOneInput(static_cast<uint8_t*>(data), length);
65   gpr_free(data);
66 }
67 
68 class ExampleGenerator
69     : public ::testing::internal::ParamGeneratorInterface<std::string> {
70  public:
71   ::testing::internal::ParamIteratorInterface<std::string>* Begin()
72       const override;
73   ::testing::internal::ParamIteratorInterface<std::string>* End()
74       const override;
75 
76  private:
Materialize() const77   void Materialize() const {
78     if (examples_.empty()) {
79       if (!absl::GetFlag(FLAGS_file).empty()) {
80         examples_.push_back(absl::GetFlag(FLAGS_file));
81       }
82       if (!absl::GetFlag(FLAGS_directory).empty()) {
83         auto test_srcdir = grpc_core::GetEnv("TEST_SRCDIR");
84         gpr_log(GPR_DEBUG, "test_srcdir=\"%s\"",
85                 test_srcdir.has_value() ? test_srcdir->c_str() : "(null)");
86         std::string directory = absl::GetFlag(FLAGS_directory);
87         if (test_srcdir.has_value()) {
88           directory =
89               *test_srcdir + std::string("/com_github_grpc_grpc/") + directory;
90         }
91         gpr_log(GPR_DEBUG, "Using corpus directory: %s", directory.c_str());
92         DIR* dp;
93         struct dirent* ep;
94         dp = opendir(directory.c_str());
95 
96         if (dp != nullptr) {
97           while ((ep = readdir(dp)) != nullptr) {
98             if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) {
99               examples_.push_back(directory + "/" + ep->d_name);
100             }
101           }
102 
103           (void)closedir(dp);
104         } else {
105           perror("Couldn't open the directory");
106           abort();
107         }
108       }
109     }
110     // Make sure we don't succeed without doing anything, which caused
111     // us to be blind to our fuzzers not running for 9 months.
112     GPR_ASSERT(!examples_.empty());
113     // Get a consistent ordering of examples so problems don't just show up on
114     // CI
115     std::sort(examples_.begin(), examples_.end());
116   }
117 
118   mutable std::vector<std::string> examples_;
119 };
120 
121 class ExampleIterator
122     : public ::testing::internal::ParamIteratorInterface<std::string> {
123  public:
ExampleIterator(const ExampleGenerator & base_,std::vector<std::string>::const_iterator begin)124   ExampleIterator(const ExampleGenerator& base_,
125                   std::vector<std::string>::const_iterator begin)
126       : base_(base_), begin_(begin), current_(begin) {}
127 
BaseGenerator() const128   const ExampleGenerator* BaseGenerator() const override { return &base_; }
129 
Advance()130   void Advance() override { current_++; }
Clone() const131   ExampleIterator* Clone() const override { return new ExampleIterator(*this); }
Current() const132   const std::string* Current() const override { return &*current_; }
133 
Equals(const ParamIteratorInterface<std::string> & other) const134   bool Equals(const ParamIteratorInterface<std::string>& other) const override {
135     return &base_ == other.BaseGenerator() &&
136            current_ == dynamic_cast<const ExampleIterator*>(&other)->current_;
137   }
138 
139  private:
ExampleIterator(const ExampleIterator & other)140   ExampleIterator(const ExampleIterator& other)
141       : base_(other.base_), begin_(other.begin_), current_(other.current_) {}
142 
143   const ExampleGenerator& base_;
144   const std::vector<std::string>::const_iterator begin_;
145   std::vector<std::string>::const_iterator current_;
146 };
147 
148 ::testing::internal::ParamIteratorInterface<std::string>*
Begin() const149 ExampleGenerator::Begin() const {
150   Materialize();
151   return new ExampleIterator(*this, examples_.begin());
152 }
153 
154 ::testing::internal::ParamIteratorInterface<std::string>*
End() const155 ExampleGenerator::End() const {
156   Materialize();
157   return new ExampleIterator(*this, examples_.end());
158 }
159 
160 INSTANTIATE_TEST_SUITE_P(
161     CorpusExamples, FuzzerCorpusTest,
162     ::testing::internal::ParamGenerator<std::string>(new ExampleGenerator));
163 
main(int argc,char ** argv)164 int main(int argc, char** argv) {
165   grpc::testing::TestEnvironment env(&argc, argv);
166   grpc::testing::InitTest(&argc, &argv, true);
167   ::testing::InitGoogleTest(&argc, argv);
168 
169   return RUN_ALL_TESTS();
170 }
171