blob: afb69409dd64d8debc2cf72806bec7e6ee484691 [file] [log] [blame]
Vitaly Bukab5c12da2016-10-19 13:12:41 -07001// 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
Vitaly Bukaf90698f2017-03-01 15:46:58 -080015#ifndef SRC_MUTATOR_H_
16#define SRC_MUTATOR_H_
Vitaly Bukab5c12da2016-10-19 13:12:41 -070017
Vitaly Buka781853c2016-11-21 23:09:35 -080018#include <stddef.h>
19#include <stdint.h>
20
Allen-Webbc4fa5912018-09-07 15:53:30 -070021#include <functional>
Vitaly Buka781853c2016-11-21 23:09:35 -080022#include <memory>
Vitaly Buka0e17fd72016-11-18 10:02:46 -080023#include <random>
Vitaly Bukaf047a002017-01-12 23:57:00 -080024#include <string>
Allen-Webbc4fa5912018-09-07 15:53:30 -070025#include <unordered_map>
26#include <vector>
Vitaly Buka00b61072016-10-19 16:22:51 -070027
Vitaly Buka35df2e42017-02-25 01:17:25 -080028#include "port/protobuf.h"
Vitaly Bukaf62fe472017-03-01 23:05:15 -080029#include "src/random.h"
Vitaly Bukab5c12da2016-10-19 13:12:41 -070030
Vitaly Buka432b5452016-12-09 14:42:09 -080031namespace protobuf_mutator {
32
Vitaly Buka4af611d2016-12-03 18:57:32 -080033// Randomly makes incremental change in the given protobuf.
34// Usage example:
Vitaly Bukae79e0182017-03-01 16:02:14 -080035// protobuf_mutator::Mutator mutator(1);
Vitaly Buka4af611d2016-12-03 18:57:32 -080036// MyMessage message;
37// message.ParseFromString(encoded_message);
Vitaly Buka4a6d6fc2016-12-16 14:21:37 -080038// mutator.Mutate(&message, 10000);
Vitaly Buka4af611d2016-12-03 18:57:32 -080039//
Vitaly Buka432b5452016-12-09 14:42:09 -080040// 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
Vitaly Bukae79e0182017-03-01 16:02:14 -080043// protobuf_mutator::Mutator::Mutate* methods with more useful logic, e.g. using
44// library like libFuzzer.
45class Mutator {
Vitaly Bukab5c12da2016-10-19 13:12:41 -070046 public:
Vitaly Buka4af611d2016-12-03 18:57:32 -080047 // seed: value to initialize random number generator.
Vitaly Buka379f5ab2019-08-31 16:11:59 -070048 Mutator() = default;
Vitaly Bukae79e0182017-03-01 16:02:14 -080049 virtual ~Mutator() = default;
Vitaly Buka781853c2016-11-21 23:09:35 -080050
Vitaly Buka379f5ab2019-08-31 16:11:59 -070051 // Initialized internal random number generator.
52 void Seed(uint32_t value);
53
Vitaly Buka4af611d2016-12-03 18:57:32 -080054 // message: message to mutate.
Vitaly Bukabaa13292020-01-25 19:39:28 -080055 // 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);
Vitaly Buka4af611d2016-12-03 18:57:32 -080059
Vitaly Buka9f357ae2020-01-26 23:17:11 -080060 void CrossOver(const protobuf::Message& message1, protobuf::Message* message2,
61 size_t max_size_hint);
Vitaly Bukab5c12da2016-10-19 13:12:41 -070062
Vitaly Bukad82b5fb2020-07-28 23:41:42 -070063 // Makes message initialized and calls post processors to make it valid.
64 void Fix(protobuf::Message* message);
65
Vitaly Buka67387f72019-08-31 19:34:10 -070066 // 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.
Peter Foleyfe76ed62019-09-30 17:03:37 -070074 void RegisterPostProcessor(const protobuf::Descriptor* desc,
75 PostProcess callback);
Allen-Webbc4fa5912018-09-07 15:53:30 -070076
Vitaly Buka432b5452016-12-09 14:42:09 -080077 protected:
Vitaly Bukab93a1462017-01-06 17:52:58 -080078 // TODO(vitalybuka): Consider to replace with single mutate (uint8_t*, size).
Vitaly Buka4af611d2016-12-03 18:57:32 -080079 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,
Vitaly Buka1c91e722020-01-25 21:56:22 -080088 int size_increase_hint);
Vitaly Buka4af611d2016-12-03 18:57:32 -080089
Vitaly Buka379f5ab2019-08-31 16:11:59 -070090 RandomEngine* random() { return &random_; }
Vitaly Buka68e49ad2017-02-24 14:24:31 -080091
Vitaly Bukab5c12da2016-10-19 13:12:41 -070092 private:
Vitaly Buka5d013202017-02-24 16:50:11 -080093 friend class FieldMutator;
Vitaly Bukae79e0182017-03-01 16:02:14 -080094 friend class TestMutator;
Vitaly Bukaf62086c2020-01-29 01:11:23 -080095 bool MutateImpl(const std::vector<const protobuf::Message*>& sources,
96 const std::vector<protobuf::Message*>& messages,
Vitaly Buka9f357ae2020-01-26 23:17:11 -080097 bool copy_clone_only, int size_increase_hint);
Vitaly Bukaaf8136f2017-06-09 16:40:12 -070098 std::string MutateUtf8String(const std::string& value,
Vitaly Buka1c91e722020-01-25 21:56:22 -080099 int size_increase_hint);
Vitaly Buka9eaf0632020-01-15 17:30:20 -0800100 bool IsInitialized(const protobuf::Message& message) const;
Vitaly Bukaba129722016-12-14 17:29:15 -0800101 bool keep_initialized_ = true;
Vitaly Bukad7f943f2019-01-31 14:05:33 -0800102 size_t random_to_default_ratio_ = 100;
Vitaly Buka379f5ab2019-08-31 16:11:59 -0700103 RandomEngine random_;
Vitaly Buka045acda2020-01-29 00:26:35 -0800104 using PostProcessors =
105 std::unordered_multimap<const protobuf::Descriptor*, PostProcess>;
106 PostProcessors post_processors_;
Vitaly Bukab5c12da2016-10-19 13:12:41 -0700107};
108
Vitaly Buka432b5452016-12-09 14:42:09 -0800109} // namespace protobuf_mutator
110
Vitaly Bukaf90698f2017-03-01 15:46:58 -0800111#endif // SRC_MUTATOR_H_