1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SRC_MUTATOR_H_
16 #define SRC_MUTATOR_H_
17 
18 #include <stddef.h>
19 #include <stdint.h>
20 
21 #include <functional>
22 #include <memory>
23 #include <random>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27 
28 #include "port/protobuf.h"
29 #include "src/random.h"
30 
31 namespace protobuf_mutator {
32 
33 // Randomly makes incremental change in the given protobuf.
34 // Usage example:
35 //    protobuf_mutator::Mutator mutator(1);
36 //    MyMessage message;
37 //    message.ParseFromString(encoded_message);
38 //    mutator.Mutate(&message, 10000);
39 //
40 // Class implements very basic mutations of fields. E.g. it just flips bits for
41 // integers, floats and strings. Also it increases, decreases size of
42 // strings only by one. For better results users should override
43 // protobuf_mutator::Mutator::Mutate* methods with more useful logic, e.g. using
44 // library like libFuzzer.
45 class Mutator {
46  public:
47   // seed: value to initialize random number generator.
48   Mutator() = default;
49   virtual ~Mutator() = default;
50 
51   // Initialized internal random number generator.
52   void Seed(uint32_t value);
53 
54   // message: message to mutate.
55   // max_size_hint: approximate max ByteSize() of resulting message. Method does
56   // not guarantee that real result will be strictly smaller than value. Caller
57   // could repeat mutation if result was larger than expected.
58   void Mutate(protobuf::Message* message, size_t max_size_hint);
59 
60   void CrossOver(const protobuf::Message& message1, protobuf::Message* message2,
61                  size_t max_size_hint);
62 
63   // Makes message initialized and calls post processors to make it valid.
64   void Fix(protobuf::Message* message);
65 
66   // Callback to postprocess mutations.
67   // Implementation should use seed to initialize random number generators.
68   using PostProcess =
69       std::function<void(protobuf::Message* message, unsigned int seed)>;
70 
71   // Register callback which will be called after every message mutation.
72   // In this callback fuzzer may adjust content of the message or mutate some
73   // fields in some fuzzer specific way.
74   void RegisterPostProcessor(const protobuf::Descriptor* desc,
75                              PostProcess callback);
76 
77  protected:
78   // TODO(vitalybuka): Consider to replace with single mutate (uint8_t*, size).
79   virtual int32_t MutateInt32(int32_t value);
80   virtual int64_t MutateInt64(int64_t value);
81   virtual uint32_t MutateUInt32(uint32_t value);
82   virtual uint64_t MutateUInt64(uint64_t value);
83   virtual float MutateFloat(float value);
84   virtual double MutateDouble(double value);
85   virtual bool MutateBool(bool value);
86   virtual size_t MutateEnum(size_t index, size_t item_count);
87   virtual std::string MutateString(const std::string& value,
88                                    int size_increase_hint);
89 
random()90   RandomEngine* random() { return &random_; }
91 
92  private:
93   friend class FieldMutator;
94   friend class TestMutator;
95   bool MutateImpl(const std::vector<const protobuf::Message*>& sources,
96                   const std::vector<protobuf::Message*>& messages,
97                   bool copy_clone_only, int size_increase_hint);
98   std::string MutateUtf8String(const std::string& value,
99                                int size_increase_hint);
100   bool IsInitialized(const protobuf::Message& message) const;
101   bool keep_initialized_ = true;
102   size_t random_to_default_ratio_ = 100;
103   RandomEngine random_;
104   using PostProcessors =
105       std::unordered_multimap<const protobuf::Descriptor*, PostProcess>;
106   PostProcessors post_processors_;
107 };
108 
109 }  // namespace protobuf_mutator
110 
111 #endif  // SRC_MUTATOR_H_
112