blob: e0801528470a407cee1b1b12069d59c00ffcf190 [file] [log] [blame]
Vitaly Buka00b61072016-10-19 23:22:511// 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 08:48:3115#include "src/protobuf_mutator.h"
Vitaly Buka00b61072016-10-19 23:22:5116
Vitaly Buka781853c2016-11-22 07:09:3517#include <algorithm>
Vitaly Buka0e17fd72016-11-18 18:02:4618#include <iostream>
19#include <map>
Vitaly Buka781853c2016-11-22 07:09:3520#include <random>
Vitaly Buka0e17fd72016-11-18 18:02:4621#include <string>
Vitaly Buka00b61072016-10-19 23:22:5122
Vitaly Buka9dd2f8e2017-01-13 08:48:3123#include "src/field_instance.h"
24#include "src/weighted_reservoir_sampler.h"
Vitaly Buka00b61072016-10-19 23:22:5125
Vitaly Bukaf86815c2017-02-27 22:19:1926namespace protobuf_mutator {
27
Vitaly Buka6c6dbbe2017-02-22 21:58:2428using protobuf::Descriptor;
29using protobuf::EnumDescriptor;
30using protobuf::EnumValueDescriptor;
31using protobuf::FieldDescriptor;
Vitaly Buka796b1122017-03-03 22:42:0232using protobuf::FileDescriptor;
Vitaly Buka6c6dbbe2017-02-22 21:58:2433using protobuf::Message;
34using protobuf::OneofDescriptor;
35using protobuf::Reflection;
Vitaly Buka4782c142017-03-04 08:12:3236using protobuf::util::MessageDifferencer;
Vitaly Buka796b1122017-03-03 22:42:0237using std::placeholders::_1;
Vitaly Buka0e17fd72016-11-18 18:02:4638
39namespace {
40
Vitaly Buka72019dc2016-12-15 03:17:2441const size_t kMaxInitializeDepth = 32;
42const size_t kDeletionThreshold = 128;
43const uint64_t kMutateWeight = 1000000;
Vitaly Buka0e17fd72016-11-18 18:02:4644
45enum class Mutation {
Vitaly Buka30de3092016-11-18 19:39:0746 None,
Vitaly Buka4af611d2016-12-04 02:57:3247 Add, // Adds new field with default value.
48 Mutate, // Mutates field contents.
49 Delete, // Deletes field.
Vitaly Bukaa3e59c72016-12-07 00:53:5650 Copy, // Copy values copied from another field.
Vitaly Buka4af611d2016-12-04 02:57:3251
Vitaly Buka432b5452016-12-09 22:42:0952 // TODO(vitalybuka):
53 // Clone, // Adds new field with value copied from another field.
Vitaly Buka0e17fd72016-11-18 18:02:4654};
55
Vitaly Bukab592ff02017-03-03 22:35:5256// 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-04 02:57:3263// Flips random bit in the buffer.
64void FlipBit(size_t size, uint8_t* bytes,
65 ProtobufMutator::RandomEngine* random) {
Vitaly Bukab592ff02017-03-03 22:35:5266 size_t bit = GetRandomIndex(random, size * 8);
Vitaly Buka4af611d2016-12-04 02:57:3267 bytes[bit / 8] ^= (1u << (bit % 8));
68}
Vitaly Buka781853c2016-11-22 07:09:3569
Vitaly Buka4af611d2016-12-04 02:57:3270// 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-22 07:09:3576
Vitaly Bukabeb90802017-02-28 23:28:1077// 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 Buka28ca0ee2017-03-05 05:35:4282bool IsProto3SimpleField(const FieldDescriptor& field) {
83 assert(field.file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ||
84 field.file()->syntax() == FileDescriptor::SYNTAX_PROTO2);
85 return field.file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
86 field.cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
87 !field.containing_oneof() && !field.is_repeated();
88}
89
Vitaly Bukad4ab1e72017-03-04 07:51:1990struct CreateDefaultField : public FieldFunction<CreateDefaultField> {
Vitaly Buka91ad7b02016-12-12 23:41:4191 template <class T>
Vitaly Bukad4ab1e72017-03-04 07:51:1992 void ForType(const FieldInstance& field) const {
Vitaly Buka91ad7b02016-12-12 23:41:4193 T value;
94 field.GetDefault(&value);
95 field.Create(value);
Vitaly Bukabec52222016-12-09 22:29:3296 }
Vitaly Buka91ad7b02016-12-12 23:41:4197};
Vitaly Bukabec52222016-12-09 22:29:3298
Vitaly Bukad4ab1e72017-03-04 07:51:1999struct DeleteField : public FieldFunction<DeleteField> {
Vitaly Buka91ad7b02016-12-12 23:41:41100 template <class T>
Vitaly Bukad4ab1e72017-03-04 07:51:19101 void ForType(const FieldInstance& field) const {
Vitaly Buka91ad7b02016-12-12 23:41:41102 field.Delete();
Vitaly Bukabec52222016-12-09 22:29:32103 }
Vitaly Bukabec52222016-12-09 22:29:32104};
105
Vitaly Bukad4ab1e72017-03-04 07:51:19106struct CopyField : public FieldFunction<CopyField> {
Vitaly Bukaa3e59c72016-12-07 00:53:56107 template <class T>
Vitaly Bukad4ab1e72017-03-04 07:51:19108 void ForType(const ConstFieldInstance& source,
109 const FieldInstance& field) const {
Vitaly Bukaa3e59c72016-12-07 00:53:56110 T value;
111 source.Load(&value);
112 field.Store(value);
113 }
Vitaly Bukaa3e59c72016-12-07 00:53:56114};
115
Vitaly Bukad4ab1e72017-03-04 07:51:19116struct AppendField : public FieldFunction<AppendField> {
Vitaly Bukaadfc27c2017-02-27 06:36:36117 template <class T>
Vitaly Bukad4ab1e72017-03-04 07:51:19118 void ForType(const ConstFieldInstance& source,
119 const FieldInstance& field) const {
Vitaly Bukaadfc27c2017-02-27 06:36:36120 T value;
121 source.Load(&value);
122 field.Create(value);
123 }
Vitaly Bukaadfc27c2017-02-27 06:36:36124};
125
Vitaly Buka4782c142017-03-04 08:12:32126class IsEqualValueField : public FieldFunction<IsEqualValueField, bool> {
127 public:
128 template <class T>
129 bool ForType(const ConstFieldInstance& a, const ConstFieldInstance& b) const {
130 T aa;
131 a.Load(&aa);
132 T bb;
133 b.Load(&bb);
134 return IsEqual(aa, bb);
135 }
136
137 private:
138 bool IsEqual(const ConstFieldInstance::Enum& a,
139 const ConstFieldInstance::Enum& b) const {
140 assert(a.count == b.count);
141 return a.index == b.index;
142 }
143
144 bool IsEqual(const std::unique_ptr<protobuf::Message>& a,
145 const std::unique_ptr<protobuf::Message>& b) const {
146 return MessageDifferencer::Equals(*a, *b);
147 }
148
149 template <class T>
150 bool IsEqual(const T& a, const T& b) const {
151 return a == b;
152 }
153};
154
Vitaly Buka4af611d2016-12-04 02:57:32155// Selects random field and mutation from the given proto message.
Vitaly Buka781853c2016-11-22 07:09:35156class MutationSampler {
Vitaly Bukac9d22482016-11-21 21:29:17157 public:
Vitaly Buka72019dc2016-12-15 03:17:24158 MutationSampler(bool keep_initialized, size_t size_increase_hint,
Vitaly Buka781853c2016-11-22 07:09:35159 ProtobufMutator::RandomEngine* random, Message* message)
Vitaly Buka4af611d2016-12-04 02:57:32160 : keep_initialized_(keep_initialized), random_(random), sampler_(random) {
Vitaly Buka72019dc2016-12-15 03:17:24161 if (size_increase_hint < kDeletionThreshold) {
Vitaly Buka4af611d2016-12-04 02:57:32162 // Avoid adding new field and prefer deleting fields if we getting close
163 // to the limit.
Vitaly Buka72019dc2016-12-15 03:17:24164 float adjustment = 0.5 * size_increase_hint / kDeletionThreshold;
165 add_weight_ *= adjustment;
166 delete_weight_ *= 1 - adjustment;
Vitaly Buka781853c2016-11-22 07:09:35167 }
168 Sample(message);
Vitaly Bukabec52222016-12-09 22:29:32169 assert(mutation() != Mutation::None);
Vitaly Bukac9d22482016-11-21 21:29:17170 }
171
Vitaly Buka4af611d2016-12-04 02:57:32172 // Returns selected field.
Vitaly Bukabec52222016-12-09 22:29:32173 const FieldInstance& field() const { return sampler_.selected().field; }
Vitaly Buka4af611d2016-12-04 02:57:32174
175 // Returns selected mutation.
Vitaly Buka432b5452016-12-09 22:42:09176 Mutation mutation() const { return sampler_.selected().mutation; }
Vitaly Buka4af611d2016-12-04 02:57:32177
178 private:
Vitaly Buka781853c2016-11-22 07:09:35179 void Sample(Message* message) {
180 const Descriptor* descriptor = message->GetDescriptor();
181 const Reflection* reflection = message->GetReflection();
182
183 int field_count = descriptor->field_count();
184 for (int i = 0; i < field_count; ++i) {
185 const FieldDescriptor* field = descriptor->field(i);
186 if (const OneofDescriptor* oneof = field->containing_oneof()) {
187 // Handle entire oneof group on the first field.
188 if (field->index_in_oneof() == 0) {
Vitaly Buka2f660a52017-03-04 03:46:14189 assert(oneof->field_count());
190 const FieldDescriptor* current_field =
191 reflection->GetOneofFieldDescriptor(*message, oneof);
192 for (;;) {
193 const FieldDescriptor* add_field =
194 oneof->field(GetRandomIndex(random_, oneof->field_count()));
195 if (add_field != current_field) {
196 sampler_.Try(add_weight_, {{message, add_field}, Mutation::Add});
197 break;
198 }
199 if (oneof->field_count() < 2) break;
200 }
201 if (current_field) {
Vitaly Buka28ca0ee2017-03-05 05:35:42202 if (current_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
Vitaly Buka2f660a52017-03-04 03:46:14203 sampler_.Try(kMutateWeight,
204 {{message, current_field}, Mutation::Mutate});
Vitaly Buka28ca0ee2017-03-05 05:35:42205 }
Vitaly Buka2f660a52017-03-04 03:46:14206 sampler_.Try(delete_weight_,
207 {{message, current_field}, Mutation::Delete});
Vitaly Buka72019dc2016-12-15 03:17:24208 sampler_.Try(GetCopyWeight(field),
Vitaly Buka2f660a52017-03-04 03:46:14209 {{message, current_field}, Mutation::Copy});
Vitaly Buka781853c2016-11-22 07:09:35210 }
211 }
212 } else {
213 if (field->is_repeated()) {
Vitaly Bukabec52222016-12-09 22:29:32214 int field_size = reflection->FieldSize(*message, field);
215 sampler_.Try(add_weight_, {{message, field,
216 GetRandomIndex(random_, field_size + 1)},
217 Mutation::Add});
Vitaly Buka781853c2016-11-22 07:09:35218
Vitaly Bukabec52222016-12-09 22:29:32219 if (field_size) {
220 size_t random_index = GetRandomIndex(random_, field_size);
Vitaly Buka28ca0ee2017-03-05 05:35:42221 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
Vitaly Bukabec52222016-12-09 22:29:32222 sampler_.Try(kMutateWeight,
223 {{message, field, random_index}, Mutation::Mutate});
Vitaly Buka28ca0ee2017-03-05 05:35:42224 }
Vitaly Bukabec52222016-12-09 22:29:32225 sampler_.Try(delete_weight_,
226 {{message, field, random_index}, Mutation::Delete});
Vitaly Buka72019dc2016-12-15 03:17:24227 sampler_.Try(GetCopyWeight(field),
Vitaly Bukaa3e59c72016-12-07 00:53:56228 {{message, field, random_index}, Mutation::Copy});
Vitaly Buka781853c2016-11-22 07:09:35229 }
230 } else {
Vitaly Buka28ca0ee2017-03-05 05:35:42231 if (reflection->HasField(*message, field) ||
232 IsProto3SimpleField(*field)) {
Vitaly Buka4af611d2016-12-04 02:57:32233 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
Vitaly Bukabec52222016-12-09 22:29:32234 sampler_.Try(kMutateWeight, {{message, field}, Mutation::Mutate});
Vitaly Buka28ca0ee2017-03-05 05:35:42235 if (!IsProto3SimpleField(*field) &&
236 (!field->is_required() || !keep_initialized_)) {
Vitaly Bukabec52222016-12-09 22:29:32237 sampler_.Try(delete_weight_,
238 {{message, field}, Mutation::Delete});
Vitaly Buka28ca0ee2017-03-05 05:35:42239 }
Vitaly Buka72019dc2016-12-15 03:17:24240 sampler_.Try(GetCopyWeight(field),
241 {{message, field}, Mutation::Copy});
Vitaly Buka781853c2016-11-22 07:09:35242 } else {
Vitaly Bukabec52222016-12-09 22:29:32243 sampler_.Try(add_weight_, {{message, field}, Mutation::Add});
Vitaly Buka781853c2016-11-22 07:09:35244 }
245 }
246 }
247
248 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
249 if (field->is_repeated()) {
250 const int field_size = reflection->FieldSize(*message, field);
251 for (int j = 0; j < field_size; ++j)
252 Sample(reflection->MutableRepeatedMessage(message, field, j));
253 } else if (reflection->HasField(*message, field)) {
254 Sample(reflection->MutableMessage(message, field));
255 }
256 }
257 }
258 }
259
Vitaly Buka72019dc2016-12-15 03:17:24260 uint64_t GetCopyWeight(const FieldDescriptor* field) const {
261 // Coping sub-messages can increase size significantly.
262 return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
263 ? add_weight_
264 : kMutateWeight;
265 }
266
Vitaly Buka781853c2016-11-22 07:09:35267 bool keep_initialized_ = false;
Vitaly Buka4af611d2016-12-04 02:57:32268
269 // Adding and deleting are intrusive and expensive mutations, we'd like to do
Vitaly Buka432b5452016-12-09 22:42:09270 // them less often than field mutations.
Vitaly Buka781853c2016-11-22 07:09:35271 uint64_t add_weight_ = kMutateWeight / 10;
272 uint64_t delete_weight_ = kMutateWeight / 10;
Vitaly Buka781853c2016-11-22 07:09:35273
Vitaly Buka4af611d2016-12-04 02:57:32274 ProtobufMutator::RandomEngine* random_;
275
276 struct Result {
Vitaly Buka91ad7b02016-12-12 23:41:41277 Result() = default;
Vitaly Bukabec52222016-12-09 22:29:32278 Result(const FieldInstance& f, Mutation m) : field(f), mutation(m) {}
Vitaly Buka91ad7b02016-12-12 23:41:41279
Vitaly Bukabec52222016-12-09 22:29:32280 FieldInstance field;
281 Mutation mutation = Mutation::None;
Vitaly Buka4af611d2016-12-04 02:57:32282 };
283 WeightedReservoirSampler<Result, ProtobufMutator::RandomEngine> sampler_;
Vitaly Bukac9d22482016-11-21 21:29:17284};
285
Vitaly Bukaa3e59c72016-12-07 00:53:56286// Selects random field of compatible type to use for clone mutations.
287class DataSourceSampler {
288 public:
Vitaly Buka88712862017-02-27 06:21:30289 DataSourceSampler(const ConstFieldInstance& match,
Vitaly Buka72019dc2016-12-15 03:17:24290 ProtobufMutator::RandomEngine* random, Message* message)
Vitaly Bukaa3e59c72016-12-07 00:53:56291 : match_(match), random_(random), sampler_(random) {
292 Sample(message);
293 }
294
295 // Returns selected field.
Vitaly Buka88712862017-02-27 06:21:30296 const ConstFieldInstance& field() const {
Vitaly Buka72019dc2016-12-15 03:17:24297 assert(!IsEmpty());
298 return sampler_.selected();
299 }
300
301 bool IsEmpty() const { return sampler_.IsEmpty(); }
Vitaly Bukaa3e59c72016-12-07 00:53:56302
303 private:
304 void Sample(Message* message) {
305 const Descriptor* descriptor = message->GetDescriptor();
306 const Reflection* reflection = message->GetReflection();
307
308 int field_count = descriptor->field_count();
309 for (int i = 0; i < field_count; ++i) {
310 const FieldDescriptor* field = descriptor->field(i);
311 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
312 if (field->is_repeated()) {
313 const int field_size = reflection->FieldSize(*message, field);
314 for (int j = 0; j < field_size; ++j) {
315 Sample(reflection->MutableRepeatedMessage(message, field, j));
316 }
317 } else if (reflection->HasField(*message, field)) {
318 Sample(reflection->MutableMessage(message, field));
319 }
320 }
321
322 if (field->cpp_type() != match_.cpp_type()) continue;
323 if (match_.cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
324 if (field->enum_type() != match_.enum_type()) continue;
325 } else if (match_.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
326 if (field->message_type() != match_.message_type()) continue;
327 }
328
Vitaly Bukaa3e59c72016-12-07 00:53:56329 if (field->is_repeated()) {
330 if (int field_size = reflection->FieldSize(*message, field)) {
Vitaly Buka4782c142017-03-04 08:12:32331 ConstFieldInstance source(message, field,
332 GetRandomIndex(random_, field_size));
333 if (!IsEqualValueField()(match_, source))
334 sampler_.Try(field_size, source);
Vitaly Bukaa3e59c72016-12-07 00:53:56335 }
336 } else {
337 if (reflection->HasField(*message, field)) {
Vitaly Buka4782c142017-03-04 08:12:32338 ConstFieldInstance source(message, field);
339 if (!IsEqualValueField()(match_, source)) sampler_.Try(1, source);
Vitaly Bukaa3e59c72016-12-07 00:53:56340 }
341 }
342 }
343 }
344
Vitaly Buka88712862017-02-27 06:21:30345 ConstFieldInstance match_;
Vitaly Bukaa3e59c72016-12-07 00:53:56346 ProtobufMutator::RandomEngine* random_;
347
Vitaly Buka88712862017-02-27 06:21:30348 WeightedReservoirSampler<ConstFieldInstance, ProtobufMutator::RandomEngine>
Vitaly Buka72019dc2016-12-15 03:17:24349 sampler_;
Vitaly Bukaa3e59c72016-12-07 00:53:56350};
351
Vitaly Buka0e17fd72016-11-18 18:02:46352} // namespace
353
Vitaly Buka5d013202017-02-25 00:50:11354class FieldMutator {
Vitaly Buka432b5452016-12-09 22:42:09355 public:
Vitaly Buka5d013202017-02-25 00:50:11356 FieldMutator(size_t size_increase_hint, ProtobufMutator* mutator)
357 : size_increase_hint_(size_increase_hint), mutator_(mutator) {}
Vitaly Buka91ad7b02016-12-12 23:41:41358
Vitaly Buka796b1122017-03-03 22:42:02359 void Mutate(int32_t* value) const {
360 RepeatMutate(value, std::bind(&ProtobufMutator::MutateInt32, mutator_, _1));
361 }
Vitaly Buka91ad7b02016-12-12 23:41:41362
Vitaly Buka796b1122017-03-03 22:42:02363 void Mutate(int64_t* value) const {
364 RepeatMutate(value, std::bind(&ProtobufMutator::MutateInt64, mutator_, _1));
365 }
Vitaly Buka91ad7b02016-12-12 23:41:41366
367 void Mutate(uint32_t* value) const {
Vitaly Buka796b1122017-03-03 22:42:02368 RepeatMutate(value,
369 std::bind(&ProtobufMutator::MutateUInt32, mutator_, _1));
Vitaly Buka91ad7b02016-12-12 23:41:41370 }
371
372 void Mutate(uint64_t* value) const {
Vitaly Buka796b1122017-03-03 22:42:02373 RepeatMutate(value,
374 std::bind(&ProtobufMutator::MutateUInt64, mutator_, _1));
Vitaly Buka91ad7b02016-12-12 23:41:41375 }
376
Vitaly Buka796b1122017-03-03 22:42:02377 void Mutate(float* value) const {
378 RepeatMutate(value, std::bind(&ProtobufMutator::MutateFloat, mutator_, _1));
379 }
Vitaly Buka91ad7b02016-12-12 23:41:41380
Vitaly Buka796b1122017-03-03 22:42:02381 void Mutate(double* value) const {
382 RepeatMutate(value,
383 std::bind(&ProtobufMutator::MutateDouble, mutator_, _1));
384 }
Vitaly Buka91ad7b02016-12-12 23:41:41385
Vitaly Buka796b1122017-03-03 22:42:02386 void Mutate(bool* value) const {
387 RepeatMutate(value, std::bind(&ProtobufMutator::MutateBool, mutator_, _1));
388 }
Vitaly Buka91ad7b02016-12-12 23:41:41389
390 void Mutate(FieldInstance::Enum* value) const {
Vitaly Buka796b1122017-03-03 22:42:02391 RepeatMutate(&value->index, std::bind(&ProtobufMutator::MutateEnum,
392 mutator_, _1, value->count));
Vitaly Buka91ad7b02016-12-12 23:41:41393 assert(value->index < value->count);
394 }
395
396 void Mutate(std::string* value) const {
Vitaly Buka796b1122017-03-03 22:42:02397 RepeatMutate(value, std::bind(&ProtobufMutator::MutateString, mutator_, _1,
398 size_increase_hint_));
Vitaly Buka91ad7b02016-12-12 23:41:41399 }
400
Vitaly Buka6c6dbbe2017-02-22 21:58:24401 void Mutate(std::unique_ptr<Message>*) const {
Vitaly Buka6c6dbbe2017-02-22 21:58:24402 }
Vitaly Buka432b5452016-12-09 22:42:09403
Vitaly Buka5d013202017-02-25 00:50:11404 private:
Vitaly Buka796b1122017-03-03 22:42:02405 template <class T, class F>
406 void RepeatMutate(T* value, F mutate) const {
407 T tmp = *value;
408 for (int i = 0; i < 10; ++i) {
409 *value = mutate(*value);
410 if (*value != tmp) return;
411 }
412 }
413
Vitaly Buka5d013202017-02-25 00:50:11414 size_t size_increase_hint_;
Vitaly Buka432b5452016-12-09 22:42:09415 ProtobufMutator* mutator_;
Vitaly Buka432b5452016-12-09 22:42:09416};
417
Vitaly Buka5d013202017-02-25 00:50:11418namespace {
419
Vitaly Bukad4ab1e72017-03-04 07:51:19420struct MutateField : public FieldFunction<MutateField> {
Vitaly Buka5d013202017-02-25 00:50:11421 template <class T>
Vitaly Bukad4ab1e72017-03-04 07:51:19422 void ForType(const FieldInstance& field, size_t size_increase_hint,
423 ProtobufMutator* mutator) const {
Vitaly Buka5d013202017-02-25 00:50:11424 T value;
425 field.Load(&value);
Vitaly Bukad4ab1e72017-03-04 07:51:19426 FieldMutator(size_increase_hint, mutator).Mutate(&value);
Vitaly Buka5d013202017-02-25 00:50:11427 field.Store(value);
428 }
Vitaly Buka5d013202017-02-25 00:50:11429};
430
Vitaly Bukad4ab1e72017-03-04 07:51:19431struct CreateField : public FieldFunction<CreateField> {
Vitaly Buka5d013202017-02-25 00:50:11432 public:
Vitaly Buka5d013202017-02-25 00:50:11433 template <class T>
Vitaly Buka28ca0ee2017-03-05 05:35:42434 void ForType(const FieldInstance& field, ProtobufMutator* mutator) const {
Vitaly Buka5d013202017-02-25 00:50:11435 T value;
436 field.GetDefault(&value);
Vitaly Buka28ca0ee2017-03-05 05:35:42437 FieldMutator(0, mutator).Mutate(&value);
Vitaly Buka5d013202017-02-25 00:50:11438 field.Create(value);
439 }
Vitaly Buka5d013202017-02-25 00:50:11440};
441
442} // namespace
443
Vitaly Bukaba129722016-12-15 01:29:15444ProtobufMutator::ProtobufMutator(uint32_t seed) : random_(seed) {}
Vitaly Buka432b5452016-12-09 22:42:09445
Vitaly Buka72019dc2016-12-15 03:17:24446void ProtobufMutator::Mutate(Message* message, size_t size_increase_hint) {
Vitaly Buka66d06c72017-03-04 09:22:34447 bool repeat;
448 do {
449 repeat = false;
450 MutationSampler mutation(keep_initialized_, size_increase_hint, &random_,
451 message);
452 switch (mutation.mutation()) {
453 case Mutation::None:
454 break;
455 case Mutation::Add:
456 if (GetRandomBool(&random_)) {
Vitaly Buka28ca0ee2017-03-05 05:35:42457 CreateField()(mutation.field(), this);
Vitaly Buka66d06c72017-03-04 09:22:34458 } else {
459 CreateDefaultField()(mutation.field());
460 }
461 break;
462 case Mutation::Mutate:
463 MutateField()(mutation.field(), size_increase_hint / 2, this);
464 break;
465 case Mutation::Delete:
Vitaly Bukad4ab1e72017-03-04 07:51:19466 DeleteField()(mutation.field());
Vitaly Bukaa3e59c72016-12-07 00:53:56467 break;
Vitaly Buka66d06c72017-03-04 09:22:34468 case Mutation::Copy: {
469 DataSourceSampler source(mutation.field(), &random_, message);
470 if (source.IsEmpty()) {
471 repeat = true;
472 break;
473 }
474 CopyField()(source.field(), mutation.field());
475 break;
Vitaly Bukaa3e59c72016-12-07 00:53:56476 }
Vitaly Buka66d06c72017-03-04 09:22:34477 default:
478 assert(false && "unexpected mutation");
Vitaly Bukaa3e59c72016-12-07 00:53:56479 }
Vitaly Buka66d06c72017-03-04 09:22:34480 } while (repeat);
Vitaly Buka0e17fd72016-11-18 18:02:46481
Vitaly Buka781853c2016-11-22 07:09:35482 if (keep_initialized_ && !message->IsInitialized()) {
483 InitializeMessage(message, kMaxInitializeDepth);
484 assert(message->IsInitialized());
Vitaly Buka0e17fd72016-11-18 18:02:46485 }
Vitaly Buka00b61072016-10-19 23:22:51486}
487
Vitaly Bukaadfc27c2017-02-27 06:36:36488void ProtobufMutator::CrossOver(const protobuf::Message& message1,
489 protobuf::Message* message2) {
490 CrossOverImpl(message1, message2);
491
492 if (keep_initialized_ && !message2->IsInitialized()) {
493 InitializeMessage(message2, kMaxInitializeDepth);
494 assert(message2->IsInitialized());
495 }
496}
497
498void ProtobufMutator::CrossOverImpl(const protobuf::Message& message1,
499 protobuf::Message* message2) {
500 const Descriptor* descriptor = message2->GetDescriptor();
501 const Reflection* reflection = message2->GetReflection();
502 assert(message1.GetDescriptor() == descriptor);
503 assert(message1.GetReflection() == reflection);
504
505 for (int i = 0; i < descriptor->field_count(); ++i) {
506 const FieldDescriptor* field = descriptor->field(i);
507
508 if (field->is_repeated()) {
509 const int field_size1 = reflection->FieldSize(message1, field);
510 int field_size2 = reflection->FieldSize(*message2, field);
511 for (int j = 0; j < field_size1; ++j) {
512 ConstFieldInstance source(&message1, field, j);
513 FieldInstance destination(message2, field, field_size2++);
Vitaly Bukad4ab1e72017-03-04 07:51:19514 AppendField()(source, destination);
Vitaly Bukaadfc27c2017-02-27 06:36:36515 }
516
517 assert(field_size2 == reflection->FieldSize(*message2, field));
518
519 // Shuffle
520 for (int j = 0; j < field_size2; ++j) {
521 if (int k = GetRandomIndex(&random_, field_size2 - j)) {
522 reflection->SwapElements(message2, field, j, j + k);
523 }
524 }
525
526 int keep = GetRandomIndex(&random_, field_size2 + 1);
527
528 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
529 int remove = field_size2 - keep;
530 // Cross some message to keep with messages to remove.
531 int cross = GetRandomIndex(&random_, std::min(keep, remove) + 1);
532 for (int j = 0; j < cross; ++j) {
533 int k = GetRandomIndex(&random_, keep);
534 int r = keep + GetRandomIndex(&random_, remove);
535 assert(k != r);
536 CrossOverImpl(reflection->GetRepeatedMessage(*message2, field, r),
537 reflection->MutableRepeatedMessage(message2, field, k));
538 }
539 }
540
541 for (int j = keep; j < field_size2; ++j)
542 reflection->RemoveLast(message2, field);
543 assert(keep == reflection->FieldSize(*message2, field));
544
545 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
546 if (!reflection->HasField(message1, field)) {
Vitaly Bukabeb90802017-02-28 23:28:10547 if (GetRandomBool(&random_))
Vitaly Bukad4ab1e72017-03-04 07:51:19548 DeleteField()(FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-27 06:36:36549 } else if (!reflection->HasField(*message2, field)) {
Vitaly Bukabeb90802017-02-28 23:28:10550 if (GetRandomBool(&random_)) {
Vitaly Bukaadfc27c2017-02-27 06:36:36551 ConstFieldInstance source(&message1, field);
Vitaly Bukad4ab1e72017-03-04 07:51:19552 CopyField()(source, FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-27 06:36:36553 }
554 } else {
555 CrossOverImpl(reflection->GetMessage(message1, field),
556 reflection->MutableMessage(message2, field));
557 }
558 } else {
Vitaly Bukabeb90802017-02-28 23:28:10559 if (GetRandomBool(&random_)) {
Vitaly Bukaadfc27c2017-02-27 06:36:36560 if (reflection->HasField(message1, field)) {
561 ConstFieldInstance source(&message1, field);
Vitaly Bukad4ab1e72017-03-04 07:51:19562 CopyField()(source, FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-27 06:36:36563 } else {
Vitaly Bukad4ab1e72017-03-04 07:51:19564 DeleteField()(FieldInstance(message2, field));
Vitaly Bukaadfc27c2017-02-27 06:36:36565 }
566 }
567 }
568 }
569}
570
Vitaly Buka72019dc2016-12-15 03:17:24571void ProtobufMutator::InitializeMessage(Message* message, size_t max_depth) {
Vitaly Buka781853c2016-11-22 07:09:35572 assert(keep_initialized_);
Vitaly Buka432b5452016-12-09 22:42:09573 // It's pointless but possible to have infinite recursion of required
574 // messages.
575 assert(max_depth);
Vitaly Buka13245af2016-11-18 21:20:12576 const Descriptor* descriptor = message->GetDescriptor();
577 const Reflection* reflection = message->GetReflection();
Vitaly Buka13245af2016-11-18 21:20:12578 for (int i = 0; i < descriptor->field_count(); ++i) {
579 const FieldDescriptor* field = descriptor->field(i);
Vitaly Buka91ad7b02016-12-12 23:41:41580 if (field->is_required() && !reflection->HasField(*message, field))
Vitaly Bukad4ab1e72017-03-04 07:51:19581 CreateDefaultField()(FieldInstance(message, field));
Vitaly Buka13245af2016-11-18 21:20:12582
Vitaly Buka781853c2016-11-22 07:09:35583 if (max_depth > 0 &&
584 field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
Vitaly Buka2cfe02b2016-11-19 00:34:09585 if (field->is_repeated()) {
586 const int field_size = reflection->FieldSize(*message, field);
587 for (int j = 0; j < field_size; ++j) {
588 Message* nested_message =
589 reflection->MutableRepeatedMessage(message, field, j);
Vitaly Buka781853c2016-11-22 07:09:35590 if (!nested_message->IsInitialized())
591 InitializeMessage(nested_message, max_depth - 1);
Vitaly Buka2cfe02b2016-11-19 00:34:09592 }
593 } else if (reflection->HasField(*message, field)) {
594 Message* nested_message = reflection->MutableMessage(message, field);
Vitaly Buka781853c2016-11-22 07:09:35595 if (!nested_message->IsInitialized())
596 InitializeMessage(nested_message, max_depth - 1);
Vitaly Buka13245af2016-11-18 21:20:12597 }
598 }
599 }
600}
Vitaly Buka4af611d2016-12-04 02:57:32601
602int32_t ProtobufMutator::MutateInt32(int32_t value) {
603 return FlipBit(value, &random_);
604}
605
606int64_t ProtobufMutator::MutateInt64(int64_t value) {
607 return FlipBit(value, &random_);
608}
609
610uint32_t ProtobufMutator::MutateUInt32(uint32_t value) {
611 return FlipBit(value, &random_);
612}
613
614uint64_t ProtobufMutator::MutateUInt64(uint64_t value) {
615 return FlipBit(value, &random_);
616}
617
618float ProtobufMutator::MutateFloat(float value) {
619 return FlipBit(value, &random_);
620}
621
622double ProtobufMutator::MutateDouble(double value) {
623 return FlipBit(value, &random_);
624}
625
Vitaly Bukabeb90802017-02-28 23:28:10626bool ProtobufMutator::MutateBool(bool value) { return !value; }
Vitaly Buka4af611d2016-12-04 02:57:32627
628size_t ProtobufMutator::MutateEnum(size_t index, size_t item_count) {
Vitaly Bukabeb90802017-02-28 23:28:10629 return (index + 1 + GetRandomIndex(&random_, item_count - 1)) % item_count;
Vitaly Buka4af611d2016-12-04 02:57:32630}
631
632std::string ProtobufMutator::MutateString(const std::string& value,
Vitaly Buka5d013202017-02-25 00:50:11633 size_t size_increase_hint) {
Vitaly Buka4af611d2016-12-04 02:57:32634 std::string result = value;
Vitaly Buka5d013202017-02-25 00:50:11635
Vitaly Bukabeb90802017-02-28 23:28:10636 while (!result.empty() && GetRandomBool(&random_)) {
Vitaly Buka432b5452016-12-09 22:42:09637 result.erase(GetRandomIndex(&random_, result.size()), 1);
Vitaly Buka432b5452016-12-09 22:42:09638 }
639
Vitaly Bukabeb90802017-02-28 23:28:10640 while (result.size() < size_increase_hint && GetRandomBool(&random_)) {
Vitaly Buka432b5452016-12-09 22:42:09641 size_t index = GetRandomIndex(&random_, result.size() + 1);
Vitaly Buka5d013202017-02-25 00:50:11642 result.insert(result.begin() + index, GetRandomIndex(&random_, 1 << 8));
Vitaly Buka432b5452016-12-09 22:42:09643 }
644
Vitaly Bukac020de12017-03-04 03:36:23645 if (result != value) return result;
646
647 if (result.empty()) {
648 result.push_back(GetRandomIndex(&random_, 1 << 8));
649 return result;
650 }
651
Vitaly Buka4af611d2016-12-04 02:57:32652 if (!result.empty())
653 FlipBit(result.size(), reinterpret_cast<uint8_t*>(&result[0]), &random_);
654 return result;
655}
Vitaly Buka432b5452016-12-09 22:42:09656
657} // namespace protobuf_mutator