blob: a9838863a16d7c955ed2440aef4ec71cc4af1335 [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 Buka9dd2f8e2017-01-13 00:48:31 -080015#ifndef SRC_PROTOBUF_MUTATOR_H_
16#define SRC_PROTOBUF_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
21#include <memory>
Vitaly Buka0e17fd72016-11-18 10:02:46 -080022#include <random>
Vitaly Bukaf047a002017-01-12 23:57:00 -080023#include <string>
Vitaly Buka00b61072016-10-19 16:22:51 -070024
Vitaly Buka35df2e42017-02-25 01:17:25 -080025#include "port/protobuf.h"
Vitaly Bukab5c12da2016-10-19 13:12:41 -070026
Vitaly Buka432b5452016-12-09 14:42:09 -080027namespace protobuf_mutator {
28
Vitaly Buka4af611d2016-12-03 18:57:32 -080029// Randomly makes incremental change in the given protobuf.
30// Usage example:
31// ProtobufMutator mutator(1);
32// MyMessage message;
33// message.ParseFromString(encoded_message);
Vitaly Buka4a6d6fc2016-12-16 14:21:37 -080034// mutator.Mutate(&message, 10000);
Vitaly Buka4af611d2016-12-03 18:57:32 -080035//
Vitaly Buka432b5452016-12-09 14:42:09 -080036// Class implements very basic mutations of fields. E.g. it just flips bits for
37// integers, floats and strings. Also it increases, decreases size of
38// strings only by one. For better results users should override
39// ProtobufMutator::Mutate* methods with more useful logic, e.g. using library
40// like libFuzzer.
Vitaly Bukab5c12da2016-10-19 13:12:41 -070041class ProtobufMutator {
42 public:
Vitaly Buka432b5452016-12-09 14:42:09 -080043 using RandomEngine = std::mt19937;
Vitaly Buka781853c2016-11-21 23:09:35 -080044
Vitaly Buka4af611d2016-12-03 18:57:32 -080045 // seed: value to initialize random number generator.
Vitaly Bukaba129722016-12-14 17:29:15 -080046 explicit ProtobufMutator(uint32_t seed);
Vitaly Buka6c6dbbe2017-02-22 13:58:24 -080047 virtual ~ProtobufMutator() = default;
Vitaly Buka781853c2016-11-21 23:09:35 -080048
Vitaly Buka4af611d2016-12-03 18:57:32 -080049 // message: message to mutate.
Vitaly Buka72019dc2016-12-14 19:17:24 -080050 // size_increase_hint: approximate number of bytes which can be added to the
51 // message. Method does not guarantee that real result size increase will be
52 // less than the value. It only changes probabilities of mutations which can
53 // cause size increase. Caller could repeat mutation if result was larger than
Vitaly Buka4af611d2016-12-03 18:57:32 -080054 // requested.
Vitaly Buka6c6dbbe2017-02-22 13:58:24 -080055 void Mutate(protobuf::Message* message, size_t size_increase_hint);
Vitaly Buka4af611d2016-12-03 18:57:32 -080056
Vitaly Bukaadfc27c2017-02-26 22:36:36 -080057 void CrossOver(const protobuf::Message& message1,
58 protobuf::Message* message2);
Vitaly Bukab5c12da2016-10-19 13:12:41 -070059
Vitaly Buka432b5452016-12-09 14:42:09 -080060 protected:
Vitaly Bukab93a1462017-01-06 17:52:58 -080061 // TODO(vitalybuka): Consider to replace with single mutate (uint8_t*, size).
Vitaly Buka4af611d2016-12-03 18:57:32 -080062 virtual int32_t MutateInt32(int32_t value);
63 virtual int64_t MutateInt64(int64_t value);
64 virtual uint32_t MutateUInt32(uint32_t value);
65 virtual uint64_t MutateUInt64(uint64_t value);
66 virtual float MutateFloat(float value);
67 virtual double MutateDouble(double value);
68 virtual bool MutateBool(bool value);
69 virtual size_t MutateEnum(size_t index, size_t item_count);
70 virtual std::string MutateString(const std::string& value,
Vitaly Buka5d013202017-02-24 16:50:11 -080071 size_t size_increase_hint);
Vitaly Buka4af611d2016-12-03 18:57:32 -080072
Vitaly Buka432b5452016-12-09 14:42:09 -080073 // TODO(vitalybuka): Allow user to control proto level mutations:
Vitaly Buka4af611d2016-12-03 18:57:32 -080074 // * Callbacks to recursive traversal.
75 // * Callbacks for particular proto level mutations.
Vitaly Buka2cfe02b2016-11-18 16:34:09 -080076
Vitaly Buka68e49ad2017-02-24 14:24:31 -080077 RandomEngine* random() { return &random_; }
78
Vitaly Bukab5c12da2016-10-19 13:12:41 -070079 private:
Vitaly Buka5d013202017-02-24 16:50:11 -080080 friend class FieldMutator;
Vitaly Bukaba129722016-12-14 17:29:15 -080081 friend class TestProtobufMutator;
Vitaly Buka6c6dbbe2017-02-22 13:58:24 -080082 void InitializeMessage(protobuf::Message* message, size_t max_depth);
Vitaly Bukaadfc27c2017-02-26 22:36:36 -080083 void CrossOverImpl(const protobuf::Message& message1,
84 protobuf::Message* message2);
Vitaly Buka4af611d2016-12-03 18:57:32 -080085
Vitaly Bukaba129722016-12-14 17:29:15 -080086 bool keep_initialized_ = true;
Vitaly Buka781853c2016-11-21 23:09:35 -080087 RandomEngine random_;
Vitaly Bukab5c12da2016-10-19 13:12:41 -070088};
89
Vitaly Buka432b5452016-12-09 14:42:09 -080090} // namespace protobuf_mutator
91
Vitaly Buka9dd2f8e2017-01-13 00:48:31 -080092#endif // SRC_PROTOBUF_MUTATOR_H_