blob: 248de5f1edb68c1a0ddd6838d660525f9164fd68 [file] [log] [blame]
Vitaly Buka00b61072016-10-19 16:22:51 -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#include "src/protobuf_mutator.h"
Vitaly Buka00b61072016-10-19 16:22:51 -070016
Vitaly Buka781853c2016-11-21 23:09:35 -080017#include <algorithm>
Vitaly Buka0e17fd72016-11-18 10:02:46 -080018#include <iostream>
19#include <map>
Vitaly Buka781853c2016-11-21 23:09:35 -080020#include <random>
Vitaly Buka0e17fd72016-11-18 10:02:46 -080021#include <string>
Vitaly Buka00b61072016-10-19 16:22:51 -070022
Vitaly Buka9dd2f8e2017-01-13 00:48:31 -080023#include "src/field_instance.h"
24#include "src/weighted_reservoir_sampler.h"
Vitaly Buka00b61072016-10-19 16:22:51 -070025
Vitaly Bukaf86815c2017-02-27 14:19:19 -080026namespace protobuf_mutator {
27
Vitaly Buka6c6dbbe2017-02-22 13:58:24 -080028using protobuf::Descriptor;
29using protobuf::EnumDescriptor;
30using protobuf::EnumValueDescriptor;
31using protobuf::FieldDescriptor;
Vitaly Buka796b1122017-03-03 14:42:02 -080032using protobuf::FileDescriptor;
Vitaly Buka6c6dbbe2017-02-22 13:58:24 -080033using protobuf::Message;
34using protobuf::OneofDescriptor;
35using protobuf::Reflection;
Vitaly Buka4782c142017-03-04 00:12:32 -080036using protobuf::util::MessageDifferencer;
Vitaly Buka796b1122017-03-03 14:42:02 -080037using std::placeholders::_1;
Vitaly Buka0e17fd72016-11-18 10:02:46 -080038
39namespace {
40
Vitaly Buka72019dc2016-12-14 19:17:24 -080041const size_t kMaxInitializeDepth = 32;
42const size_t kDeletionThreshold = 128;
43const uint64_t kMutateWeight = 1000000;
Vitaly Buka0e17fd72016-11-18 10:02:46 -080044
45enum class Mutation {
Vitaly Buka30de3092016-11-18 11:39:07 -080046 None,
Vitaly Buka4af611d2016-12-03 18:57:32 -080047 Add, // Adds new field with default value.
48 Mutate, // Mutates field contents.
49 Delete, // Deletes field.
Vitaly Bukaa3e59c72016-12-06 16:53:56 -080050 Copy, // Copy values copied from another field.
Vitaly Buka4af611d2016-12-03 18:57:32 -080051
Vitaly Buka432b5452016-12-09 14:42:09 -080052 // TODO(vitalybuka):
53 // Clone, // Adds new field with value copied from another field.
Vitaly Buka0e17fd72016-11-18 10:02:46 -080054};
55
Vitaly Bukab592ff02017-03-03 14:35:52 -080056// Return random integer from [0, count)
57size_t GetRandomIndex(ProtobufMutator::RandomEngine* random, size_t count) {
58 assert(count > 0);
59 if (count == 1) return 0;
60 return std::uniform_int_distribution<size_t>(0, count - 1)(*random);
61}
62
Vitaly Buka4af611d2016-12-03 18:57:32 -080063// Flips random bit in the buffer.
64void FlipBit(size_t size, uint8_t* bytes,
65 ProtobufMutator::RandomEngine* random) {
Vitaly Bukab592ff02017-03-03 14:35:52 -080066 size_t bit = GetRandomIndex(random, size * 8);
Vitaly Buka4af611d2016-12-03 18:57:32 -080067 bytes[bit / 8] ^= (1u << (bit % 8));
68}
Vitaly Buka781853c2016-11-21 23:09:35 -080069
Vitaly Buka4af611d2016-12-03 18:57:32 -080070// Flips random bit in the value.
71template <class T>
72T FlipBit(T value, ProtobufMutator::RandomEngine* random) {
73 FlipBit(sizeof(value), reinterpret_cast<uint8_t*>(&value), random);
74 return value;
75}
Vitaly Buka781853c2016-11-21 23:09:35 -080076
Vitaly Bukabeb90802017-02-28 15:28:10 -080077// Return true with probability about 1-of-n.
78bool GetRandomBool(ProtobufMutator::RandomEngine* random, size_t n = 2) {
79 return GetRandomIndex(random, n) == 0;
80}
81
Vitaly Bukad4ab1e72017-03-03 23:51:19 -080082struct CreateDefaultField : public FieldFunction<CreateDefaultField> {
Vitaly Buka91ad7b02016-12-12 15:41:41 -080083 template <class T>
Vitaly Bukad4ab1e72017-03-03 23:51:19 -080084 void ForType(const FieldInstance& field) const {
Vitaly Buka91ad7b02016-12-12 15:41:41 -080085 T value;
86 field.GetDefault(&value);
87 field.Create(value);
Vitaly Bukabec52222016-12-09 14:29:32 -080088 }
Vitaly Buka91ad7b02016-12-12 15:41:41 -080089};
Vitaly Bukabec52222016-12-09 14:29:32 -080090
Vitaly Bukad4ab1e72017-03-03 23:51:19 -080091struct DeleteField : public FieldFunction<DeleteField> {
Vitaly Buka91ad7b02016-12-12 15:41:41 -080092 template <class T>
Vitaly Bukad4ab1e72017-03-03 23:51:19 -080093 void ForType(const FieldInstance& field) const {
Vitaly Buka91ad7b02016-12-12 15:41:41 -080094 field.Delete();
Vitaly Bukabec52222016-12-09 14:29:32 -080095 }
Vitaly Bukabec52222016-12-09 14:29:32 -080096};
97
Vitaly Bukad4ab1e72017-03-03 23:51:19 -080098struct CopyField : public FieldFunction<CopyField> {
Vitaly Bukaa3e59c72016-12-06 16:53:56 -080099 template <class T>
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800100 void ForType(const ConstFieldInstance& source,
101 const FieldInstance& field) const {
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800102 T value;
103 source.Load(&value);
104 field.Store(value);
105 }
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800106};
107
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800108struct AppendField : public FieldFunction<AppendField> {
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800109 template <class T>
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800110 void ForType(const ConstFieldInstance& source,
111 const FieldInstance& field) const {
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800112 T value;
113 source.Load(&value);
114 field.Create(value);
115 }
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800116};
117
Vitaly Buka4782c142017-03-04 00:12:32 -0800118class IsEqualValueField : public FieldFunction<IsEqualValueField, bool> {
119 public:
120 template <class T>
121 bool ForType(const ConstFieldInstance& a, const ConstFieldInstance& b) const {
122 T aa;
123 a.Load(&aa);
124 T bb;
125 b.Load(&bb);
126 return IsEqual(aa, bb);
127 }
128
129 private:
130 bool IsEqual(const ConstFieldInstance::Enum& a,
131 const ConstFieldInstance::Enum& b) const {
132 assert(a.count == b.count);
133 return a.index == b.index;
134 }
135
136 bool IsEqual(const std::unique_ptr<protobuf::Message>& a,
137 const std::unique_ptr<protobuf::Message>& b) const {
138 return MessageDifferencer::Equals(*a, *b);
139 }
140
141 template <class T>
142 bool IsEqual(const T& a, const T& b) const {
143 return a == b;
144 }
145};
146
Vitaly Buka4af611d2016-12-03 18:57:32 -0800147// Selects random field and mutation from the given proto message.
Vitaly Buka781853c2016-11-21 23:09:35 -0800148class MutationSampler {
Vitaly Bukac9d22482016-11-21 13:29:17 -0800149 public:
Vitaly Buka72019dc2016-12-14 19:17:24 -0800150 MutationSampler(bool keep_initialized, size_t size_increase_hint,
Vitaly Buka781853c2016-11-21 23:09:35 -0800151 ProtobufMutator::RandomEngine* random, Message* message)
Vitaly Buka4af611d2016-12-03 18:57:32 -0800152 : keep_initialized_(keep_initialized), random_(random), sampler_(random) {
Vitaly Buka72019dc2016-12-14 19:17:24 -0800153 if (size_increase_hint < kDeletionThreshold) {
Vitaly Buka4af611d2016-12-03 18:57:32 -0800154 // Avoid adding new field and prefer deleting fields if we getting close
155 // to the limit.
Vitaly Buka72019dc2016-12-14 19:17:24 -0800156 float adjustment = 0.5 * size_increase_hint / kDeletionThreshold;
157 add_weight_ *= adjustment;
158 delete_weight_ *= 1 - adjustment;
Vitaly Buka781853c2016-11-21 23:09:35 -0800159 }
160 Sample(message);
Vitaly Bukabec52222016-12-09 14:29:32 -0800161 assert(mutation() != Mutation::None);
Vitaly Bukac9d22482016-11-21 13:29:17 -0800162 }
163
Vitaly Buka4af611d2016-12-03 18:57:32 -0800164 // Returns selected field.
Vitaly Bukabec52222016-12-09 14:29:32 -0800165 const FieldInstance& field() const { return sampler_.selected().field; }
Vitaly Buka4af611d2016-12-03 18:57:32 -0800166
167 // Returns selected mutation.
Vitaly Buka432b5452016-12-09 14:42:09 -0800168 Mutation mutation() const { return sampler_.selected().mutation; }
Vitaly Buka4af611d2016-12-03 18:57:32 -0800169
170 private:
Vitaly Buka781853c2016-11-21 23:09:35 -0800171 void Sample(Message* message) {
172 const Descriptor* descriptor = message->GetDescriptor();
173 const Reflection* reflection = message->GetReflection();
174
175 int field_count = descriptor->field_count();
176 for (int i = 0; i < field_count; ++i) {
177 const FieldDescriptor* field = descriptor->field(i);
178 if (const OneofDescriptor* oneof = field->containing_oneof()) {
179 // Handle entire oneof group on the first field.
180 if (field->index_in_oneof() == 0) {
Vitaly Buka2f660a52017-03-03 19:46:14 -0800181 assert(oneof->field_count());
182 const FieldDescriptor* current_field =
183 reflection->GetOneofFieldDescriptor(*message, oneof);
184 for (;;) {
185 const FieldDescriptor* add_field =
186 oneof->field(GetRandomIndex(random_, oneof->field_count()));
187 if (add_field != current_field) {
188 sampler_.Try(add_weight_, {{message, add_field}, Mutation::Add});
189 break;
190 }
191 if (oneof->field_count() < 2) break;
192 }
193 if (current_field) {
194 if (current_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
195 sampler_.Try(kMutateWeight,
196 {{message, current_field}, Mutation::Mutate});
197 sampler_.Try(delete_weight_,
198 {{message, current_field}, Mutation::Delete});
Vitaly Buka72019dc2016-12-14 19:17:24 -0800199 sampler_.Try(GetCopyWeight(field),
Vitaly Buka2f660a52017-03-03 19:46:14 -0800200 {{message, current_field}, Mutation::Copy});
Vitaly Buka781853c2016-11-21 23:09:35 -0800201 }
202 }
203 } else {
204 if (field->is_repeated()) {
Vitaly Bukabec52222016-12-09 14:29:32 -0800205 int field_size = reflection->FieldSize(*message, field);
206 sampler_.Try(add_weight_, {{message, field,
207 GetRandomIndex(random_, field_size + 1)},
208 Mutation::Add});
Vitaly Buka781853c2016-11-21 23:09:35 -0800209
Vitaly Bukabec52222016-12-09 14:29:32 -0800210 if (field_size) {
211 size_t random_index = GetRandomIndex(random_, field_size);
Vitaly Buka4af611d2016-12-03 18:57:32 -0800212 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
Vitaly Bukabec52222016-12-09 14:29:32 -0800213 sampler_.Try(kMutateWeight,
214 {{message, field, random_index}, Mutation::Mutate});
215 sampler_.Try(delete_weight_,
216 {{message, field, random_index}, Mutation::Delete});
Vitaly Buka72019dc2016-12-14 19:17:24 -0800217 sampler_.Try(GetCopyWeight(field),
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800218 {{message, field, random_index}, Mutation::Copy});
Vitaly Buka781853c2016-11-21 23:09:35 -0800219 }
220 } else {
221 if (reflection->HasField(*message, field)) {
Vitaly Buka4af611d2016-12-03 18:57:32 -0800222 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
Vitaly Bukabec52222016-12-09 14:29:32 -0800223 sampler_.Try(kMutateWeight, {{message, field}, Mutation::Mutate});
Vitaly Buka4af611d2016-12-03 18:57:32 -0800224 if ((!field->is_required() || !keep_initialized_))
Vitaly Bukabec52222016-12-09 14:29:32 -0800225 sampler_.Try(delete_weight_,
226 {{message, field}, Mutation::Delete});
Vitaly Buka72019dc2016-12-14 19:17:24 -0800227 sampler_.Try(GetCopyWeight(field),
228 {{message, field}, Mutation::Copy});
Vitaly Buka781853c2016-11-21 23:09:35 -0800229 } else {
Vitaly Bukabec52222016-12-09 14:29:32 -0800230 sampler_.Try(add_weight_, {{message, field}, Mutation::Add});
Vitaly Buka781853c2016-11-21 23:09:35 -0800231 }
232 }
233 }
234
235 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
236 if (field->is_repeated()) {
237 const int field_size = reflection->FieldSize(*message, field);
238 for (int j = 0; j < field_size; ++j)
239 Sample(reflection->MutableRepeatedMessage(message, field, j));
240 } else if (reflection->HasField(*message, field)) {
241 Sample(reflection->MutableMessage(message, field));
242 }
243 }
244 }
245 }
246
Vitaly Buka72019dc2016-12-14 19:17:24 -0800247 uint64_t GetCopyWeight(const FieldDescriptor* field) const {
248 // Coping sub-messages can increase size significantly.
249 return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
250 ? add_weight_
251 : kMutateWeight;
252 }
253
Vitaly Buka781853c2016-11-21 23:09:35 -0800254 bool keep_initialized_ = false;
Vitaly Buka4af611d2016-12-03 18:57:32 -0800255
256 // Adding and deleting are intrusive and expensive mutations, we'd like to do
Vitaly Buka432b5452016-12-09 14:42:09 -0800257 // them less often than field mutations.
Vitaly Buka781853c2016-11-21 23:09:35 -0800258 uint64_t add_weight_ = kMutateWeight / 10;
259 uint64_t delete_weight_ = kMutateWeight / 10;
Vitaly Buka781853c2016-11-21 23:09:35 -0800260
Vitaly Buka4af611d2016-12-03 18:57:32 -0800261 ProtobufMutator::RandomEngine* random_;
262
263 struct Result {
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800264 Result() = default;
Vitaly Bukabec52222016-12-09 14:29:32 -0800265 Result(const FieldInstance& f, Mutation m) : field(f), mutation(m) {}
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800266
Vitaly Bukabec52222016-12-09 14:29:32 -0800267 FieldInstance field;
268 Mutation mutation = Mutation::None;
Vitaly Buka4af611d2016-12-03 18:57:32 -0800269 };
270 WeightedReservoirSampler<Result, ProtobufMutator::RandomEngine> sampler_;
Vitaly Bukac9d22482016-11-21 13:29:17 -0800271};
272
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800273// Selects random field of compatible type to use for clone mutations.
274class DataSourceSampler {
275 public:
Vitaly Buka88712862017-02-26 22:21:30 -0800276 DataSourceSampler(const ConstFieldInstance& match,
Vitaly Buka72019dc2016-12-14 19:17:24 -0800277 ProtobufMutator::RandomEngine* random, Message* message)
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800278 : match_(match), random_(random), sampler_(random) {
279 Sample(message);
280 }
281
282 // Returns selected field.
Vitaly Buka88712862017-02-26 22:21:30 -0800283 const ConstFieldInstance& field() const {
Vitaly Buka72019dc2016-12-14 19:17:24 -0800284 assert(!IsEmpty());
285 return sampler_.selected();
286 }
287
288 bool IsEmpty() const { return sampler_.IsEmpty(); }
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800289
290 private:
291 void Sample(Message* message) {
292 const Descriptor* descriptor = message->GetDescriptor();
293 const Reflection* reflection = message->GetReflection();
294
295 int field_count = descriptor->field_count();
296 for (int i = 0; i < field_count; ++i) {
297 const FieldDescriptor* field = descriptor->field(i);
298 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
299 if (field->is_repeated()) {
300 const int field_size = reflection->FieldSize(*message, field);
301 for (int j = 0; j < field_size; ++j) {
302 Sample(reflection->MutableRepeatedMessage(message, field, j));
303 }
304 } else if (reflection->HasField(*message, field)) {
305 Sample(reflection->MutableMessage(message, field));
306 }
307 }
308
309 if (field->cpp_type() != match_.cpp_type()) continue;
310 if (match_.cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
311 if (field->enum_type() != match_.enum_type()) continue;
312 } else if (match_.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
313 if (field->message_type() != match_.message_type()) continue;
314 }
315
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800316 if (field->is_repeated()) {
317 if (int field_size = reflection->FieldSize(*message, field)) {
Vitaly Buka4782c142017-03-04 00:12:32 -0800318 ConstFieldInstance source(message, field,
319 GetRandomIndex(random_, field_size));
320 if (!IsEqualValueField()(match_, source))
321 sampler_.Try(field_size, source);
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800322 }
323 } else {
324 if (reflection->HasField(*message, field)) {
Vitaly Buka4782c142017-03-04 00:12:32 -0800325 ConstFieldInstance source(message, field);
326 if (!IsEqualValueField()(match_, source)) sampler_.Try(1, source);
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800327 }
328 }
329 }
330 }
331
Vitaly Buka88712862017-02-26 22:21:30 -0800332 ConstFieldInstance match_;
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800333 ProtobufMutator::RandomEngine* random_;
334
Vitaly Buka88712862017-02-26 22:21:30 -0800335 WeightedReservoirSampler<ConstFieldInstance, ProtobufMutator::RandomEngine>
Vitaly Buka72019dc2016-12-14 19:17:24 -0800336 sampler_;
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800337};
338
Vitaly Buka0e17fd72016-11-18 10:02:46 -0800339} // namespace
340
Vitaly Buka5d013202017-02-24 16:50:11 -0800341class FieldMutator {
Vitaly Buka432b5452016-12-09 14:42:09 -0800342 public:
Vitaly Buka5d013202017-02-24 16:50:11 -0800343 FieldMutator(size_t size_increase_hint, ProtobufMutator* mutator)
344 : size_increase_hint_(size_increase_hint), mutator_(mutator) {}
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800345
Vitaly Buka796b1122017-03-03 14:42:02 -0800346 void Mutate(int32_t* value) const {
347 RepeatMutate(value, std::bind(&ProtobufMutator::MutateInt32, mutator_, _1));
348 }
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800349
Vitaly Buka796b1122017-03-03 14:42:02 -0800350 void Mutate(int64_t* value) const {
351 RepeatMutate(value, std::bind(&ProtobufMutator::MutateInt64, mutator_, _1));
352 }
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800353
354 void Mutate(uint32_t* value) const {
Vitaly Buka796b1122017-03-03 14:42:02 -0800355 RepeatMutate(value,
356 std::bind(&ProtobufMutator::MutateUInt32, mutator_, _1));
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800357 }
358
359 void Mutate(uint64_t* value) const {
Vitaly Buka796b1122017-03-03 14:42:02 -0800360 RepeatMutate(value,
361 std::bind(&ProtobufMutator::MutateUInt64, mutator_, _1));
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800362 }
363
Vitaly Buka796b1122017-03-03 14:42:02 -0800364 void Mutate(float* value) const {
365 RepeatMutate(value, std::bind(&ProtobufMutator::MutateFloat, mutator_, _1));
366 }
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800367
Vitaly Buka796b1122017-03-03 14:42:02 -0800368 void Mutate(double* value) const {
369 RepeatMutate(value,
370 std::bind(&ProtobufMutator::MutateDouble, mutator_, _1));
371 }
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800372
Vitaly Buka796b1122017-03-03 14:42:02 -0800373 void Mutate(bool* value) const {
374 RepeatMutate(value, std::bind(&ProtobufMutator::MutateBool, mutator_, _1));
375 }
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800376
377 void Mutate(FieldInstance::Enum* value) const {
Vitaly Buka796b1122017-03-03 14:42:02 -0800378 RepeatMutate(&value->index, std::bind(&ProtobufMutator::MutateEnum,
379 mutator_, _1, value->count));
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800380 assert(value->index < value->count);
381 }
382
383 void Mutate(std::string* value) const {
Vitaly Buka796b1122017-03-03 14:42:02 -0800384 RepeatMutate(value, std::bind(&ProtobufMutator::MutateString, mutator_, _1,
385 size_increase_hint_));
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800386 }
387
Vitaly Buka6c6dbbe2017-02-22 13:58:24 -0800388 void Mutate(std::unique_ptr<Message>*) const {
Vitaly Buka6c6dbbe2017-02-22 13:58:24 -0800389 }
Vitaly Buka432b5452016-12-09 14:42:09 -0800390
Vitaly Buka5d013202017-02-24 16:50:11 -0800391 private:
Vitaly Buka796b1122017-03-03 14:42:02 -0800392 template <class T, class F>
393 void RepeatMutate(T* value, F mutate) const {
394 T tmp = *value;
395 for (int i = 0; i < 10; ++i) {
396 *value = mutate(*value);
397 if (*value != tmp) return;
398 }
399 }
400
Vitaly Buka5d013202017-02-24 16:50:11 -0800401 size_t size_increase_hint_;
Vitaly Buka432b5452016-12-09 14:42:09 -0800402 ProtobufMutator* mutator_;
Vitaly Buka432b5452016-12-09 14:42:09 -0800403};
404
Vitaly Buka5d013202017-02-24 16:50:11 -0800405namespace {
406
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800407struct MutateField : public FieldFunction<MutateField> {
Vitaly Buka5d013202017-02-24 16:50:11 -0800408 template <class T>
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800409 void ForType(const FieldInstance& field, size_t size_increase_hint,
410 ProtobufMutator* mutator) const {
Vitaly Buka5d013202017-02-24 16:50:11 -0800411 T value;
412 field.Load(&value);
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800413 FieldMutator(size_increase_hint, mutator).Mutate(&value);
Vitaly Buka5d013202017-02-24 16:50:11 -0800414 field.Store(value);
415 }
Vitaly Buka5d013202017-02-24 16:50:11 -0800416};
417
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800418struct CreateField : public FieldFunction<CreateField> {
Vitaly Buka5d013202017-02-24 16:50:11 -0800419 public:
Vitaly Buka5d013202017-02-24 16:50:11 -0800420 template <class T>
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800421 void ForType(const FieldInstance& field, size_t size_increase_hint,
422 ProtobufMutator* mutator) const {
Vitaly Buka5d013202017-02-24 16:50:11 -0800423 T value;
424 field.GetDefault(&value);
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800425 FieldMutator(size_increase_hint, mutator).Mutate(&value);
Vitaly Buka5d013202017-02-24 16:50:11 -0800426 field.Create(value);
427 }
Vitaly Buka5d013202017-02-24 16:50:11 -0800428};
429
430} // namespace
431
Vitaly Bukaba129722016-12-14 17:29:15 -0800432ProtobufMutator::ProtobufMutator(uint32_t seed) : random_(seed) {}
Vitaly Buka432b5452016-12-09 14:42:09 -0800433
Vitaly Buka72019dc2016-12-14 19:17:24 -0800434void ProtobufMutator::Mutate(Message* message, size_t size_increase_hint) {
Vitaly Buka66d06c72017-03-04 01:22:34 -0800435 bool repeat;
436 do {
437 repeat = false;
438 MutationSampler mutation(keep_initialized_, size_increase_hint, &random_,
439 message);
440 switch (mutation.mutation()) {
441 case Mutation::None:
442 break;
443 case Mutation::Add:
444 if (GetRandomBool(&random_)) {
445 CreateField()(mutation.field(), 0, this);
446 } else {
447 CreateDefaultField()(mutation.field());
448 }
449 break;
450 case Mutation::Mutate:
451 MutateField()(mutation.field(), size_increase_hint / 2, this);
452 break;
453 case Mutation::Delete:
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800454 DeleteField()(mutation.field());
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800455 break;
Vitaly Buka66d06c72017-03-04 01:22:34 -0800456 case Mutation::Copy: {
457 DataSourceSampler source(mutation.field(), &random_, message);
458 if (source.IsEmpty()) {
459 repeat = true;
460 break;
461 }
462 CopyField()(source.field(), mutation.field());
463 break;
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800464 }
Vitaly Buka66d06c72017-03-04 01:22:34 -0800465 default:
466 assert(false && "unexpected mutation");
Vitaly Bukaa3e59c72016-12-06 16:53:56 -0800467 }
Vitaly Buka66d06c72017-03-04 01:22:34 -0800468 } while (repeat);
Vitaly Buka0e17fd72016-11-18 10:02:46 -0800469
Vitaly Buka781853c2016-11-21 23:09:35 -0800470 if (keep_initialized_ && !message->IsInitialized()) {
471 InitializeMessage(message, kMaxInitializeDepth);
472 assert(message->IsInitialized());
Vitaly Buka0e17fd72016-11-18 10:02:46 -0800473 }
Vitaly Buka00b61072016-10-19 16:22:51 -0700474}
475
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800476void ProtobufMutator::CrossOver(const protobuf::Message& message1,
477 protobuf::Message* message2) {
478 CrossOverImpl(message1, message2);
479
480 if (keep_initialized_ && !message2->IsInitialized()) {
481 InitializeMessage(message2, kMaxInitializeDepth);
482 assert(message2->IsInitialized());
483 }
484}
485
486void ProtobufMutator::CrossOverImpl(const protobuf::Message& message1,
487 protobuf::Message* message2) {
488 const Descriptor* descriptor = message2->GetDescriptor();
489 const Reflection* reflection = message2->GetReflection();
490 assert(message1.GetDescriptor() == descriptor);
491 assert(message1.GetReflection() == reflection);
492
493 for (int i = 0; i < descriptor->field_count(); ++i) {
494 const FieldDescriptor* field = descriptor->field(i);
495
496 if (field->is_repeated()) {
497 const int field_size1 = reflection->FieldSize(message1, field);
498 int field_size2 = reflection->FieldSize(*message2, field);
499 for (int j = 0; j < field_size1; ++j) {
500 ConstFieldInstance source(&message1, field, j);
501 FieldInstance destination(message2, field, field_size2++);
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800502 AppendField()(source, destination);
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800503 }
504
505 assert(field_size2 == reflection->FieldSize(*message2, field));
506
507 // Shuffle
508 for (int j = 0; j < field_size2; ++j) {
509 if (int k = GetRandomIndex(&random_, field_size2 - j)) {
510 reflection->SwapElements(message2, field, j, j + k);
511 }
512 }
513
514 int keep = GetRandomIndex(&random_, field_size2 + 1);
515
516 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
517 int remove = field_size2 - keep;
518 // Cross some message to keep with messages to remove.
519 int cross = GetRandomIndex(&random_, std::min(keep, remove) + 1);
520 for (int j = 0; j < cross; ++j) {
521 int k = GetRandomIndex(&random_, keep);
522 int r = keep + GetRandomIndex(&random_, remove);
523 assert(k != r);
524 CrossOverImpl(reflection->GetRepeatedMessage(*message2, field, r),
525 reflection->MutableRepeatedMessage(message2, field, k));
526 }
527 }
528
529 for (int j = keep; j < field_size2; ++j)
530 reflection->RemoveLast(message2, field);
531 assert(keep == reflection->FieldSize(*message2, field));
532
533 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
534 if (!reflection->HasField(message1, field)) {
Vitaly Bukabeb90802017-02-28 15:28:10 -0800535 if (GetRandomBool(&random_))
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800536 DeleteField()(FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800537 } else if (!reflection->HasField(*message2, field)) {
Vitaly Bukabeb90802017-02-28 15:28:10 -0800538 if (GetRandomBool(&random_)) {
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800539 ConstFieldInstance source(&message1, field);
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800540 CopyField()(source, FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800541 }
542 } else {
543 CrossOverImpl(reflection->GetMessage(message1, field),
544 reflection->MutableMessage(message2, field));
545 }
546 } else {
Vitaly Bukabeb90802017-02-28 15:28:10 -0800547 if (GetRandomBool(&random_)) {
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800548 if (reflection->HasField(message1, field)) {
549 ConstFieldInstance source(&message1, field);
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800550 CopyField()(source, FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800551 } else {
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800552 DeleteField()(FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-26 22:36:36 -0800553 }
554 }
555 }
556 }
557}
558
Vitaly Buka72019dc2016-12-14 19:17:24 -0800559void ProtobufMutator::InitializeMessage(Message* message, size_t max_depth) {
Vitaly Buka781853c2016-11-21 23:09:35 -0800560 assert(keep_initialized_);
Vitaly Buka432b5452016-12-09 14:42:09 -0800561 // It's pointless but possible to have infinite recursion of required
562 // messages.
563 assert(max_depth);
Vitaly Buka13245af2016-11-18 13:20:12 -0800564 const Descriptor* descriptor = message->GetDescriptor();
565 const Reflection* reflection = message->GetReflection();
Vitaly Buka13245af2016-11-18 13:20:12 -0800566 for (int i = 0; i < descriptor->field_count(); ++i) {
567 const FieldDescriptor* field = descriptor->field(i);
Vitaly Buka91ad7b02016-12-12 15:41:41 -0800568 if (field->is_required() && !reflection->HasField(*message, field))
Vitaly Bukad4ab1e72017-03-03 23:51:19 -0800569 CreateDefaultField()(FieldInstance(message, field));
Vitaly Buka13245af2016-11-18 13:20:12 -0800570
Vitaly Buka781853c2016-11-21 23:09:35 -0800571 if (max_depth > 0 &&
572 field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
Vitaly Buka2cfe02b2016-11-18 16:34:09 -0800573 if (field->is_repeated()) {
574 const int field_size = reflection->FieldSize(*message, field);
575 for (int j = 0; j < field_size; ++j) {
576 Message* nested_message =
577 reflection->MutableRepeatedMessage(message, field, j);
Vitaly Buka781853c2016-11-21 23:09:35 -0800578 if (!nested_message->IsInitialized())
579 InitializeMessage(nested_message, max_depth - 1);
Vitaly Buka2cfe02b2016-11-18 16:34:09 -0800580 }
581 } else if (reflection->HasField(*message, field)) {
582 Message* nested_message = reflection->MutableMessage(message, field);
Vitaly Buka781853c2016-11-21 23:09:35 -0800583 if (!nested_message->IsInitialized())
584 InitializeMessage(nested_message, max_depth - 1);
Vitaly Buka13245af2016-11-18 13:20:12 -0800585 }
586 }
587 }
588}
Vitaly Buka4af611d2016-12-03 18:57:32 -0800589
590int32_t ProtobufMutator::MutateInt32(int32_t value) {
591 return FlipBit(value, &random_);
592}
593
594int64_t ProtobufMutator::MutateInt64(int64_t value) {
595 return FlipBit(value, &random_);
596}
597
598uint32_t ProtobufMutator::MutateUInt32(uint32_t value) {
599 return FlipBit(value, &random_);
600}
601
602uint64_t ProtobufMutator::MutateUInt64(uint64_t value) {
603 return FlipBit(value, &random_);
604}
605
606float ProtobufMutator::MutateFloat(float value) {
607 return FlipBit(value, &random_);
608}
609
610double ProtobufMutator::MutateDouble(double value) {
611 return FlipBit(value, &random_);
612}
613
Vitaly Bukabeb90802017-02-28 15:28:10 -0800614bool ProtobufMutator::MutateBool(bool value) { return !value; }
Vitaly Buka4af611d2016-12-03 18:57:32 -0800615
616size_t ProtobufMutator::MutateEnum(size_t index, size_t item_count) {
Vitaly Bukabeb90802017-02-28 15:28:10 -0800617 return (index + 1 + GetRandomIndex(&random_, item_count - 1)) % item_count;
Vitaly Buka4af611d2016-12-03 18:57:32 -0800618}
619
620std::string ProtobufMutator::MutateString(const std::string& value,
Vitaly Buka5d013202017-02-24 16:50:11 -0800621 size_t size_increase_hint) {
Vitaly Buka4af611d2016-12-03 18:57:32 -0800622 std::string result = value;
Vitaly Buka5d013202017-02-24 16:50:11 -0800623
Vitaly Bukabeb90802017-02-28 15:28:10 -0800624 while (!result.empty() && GetRandomBool(&random_)) {
Vitaly Buka432b5452016-12-09 14:42:09 -0800625 result.erase(GetRandomIndex(&random_, result.size()), 1);
Vitaly Buka432b5452016-12-09 14:42:09 -0800626 }
627
Vitaly Bukabeb90802017-02-28 15:28:10 -0800628 while (result.size() < size_increase_hint && GetRandomBool(&random_)) {
Vitaly Buka432b5452016-12-09 14:42:09 -0800629 size_t index = GetRandomIndex(&random_, result.size() + 1);
Vitaly Buka5d013202017-02-24 16:50:11 -0800630 result.insert(result.begin() + index, GetRandomIndex(&random_, 1 << 8));
Vitaly Buka432b5452016-12-09 14:42:09 -0800631 }
632
Vitaly Bukac020de12017-03-03 19:36:23 -0800633 if (result != value) return result;
634
635 if (result.empty()) {
636 result.push_back(GetRandomIndex(&random_, 1 << 8));
637 return result;
638 }
639
Vitaly Buka4af611d2016-12-03 18:57:32 -0800640 if (!result.empty())
641 FlipBit(result.size(), reinterpret_cast<uint8_t*>(&result[0]), &random_);
642 return result;
643}
Vitaly Buka432b5452016-12-09 14:42:09 -0800644
645} // namespace protobuf_mutator