blob: ae66fe6746265e41f26d13527b2169ea0cc3629a [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
15#include "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 Buka0e17fd72016-11-18 18:02:4623#include "google/protobuf/message.h"
Vitaly Buka91ad7b02016-12-12 23:41:4124
25#include "field_instance.h"
Vitaly Buka4af611d2016-12-04 02:57:3226#include "weighted_reservoir_sampler.h"
Vitaly Buka00b61072016-10-19 23:22:5127
Vitaly Buka0e17fd72016-11-18 18:02:4628using google::protobuf::Descriptor;
Vitaly Buka2cfe02b2016-11-19 00:34:0929using google::protobuf::EnumDescriptor;
30using google::protobuf::EnumValueDescriptor;
31using google::protobuf::FieldDescriptor;
32using google::protobuf::Message;
Vitaly Buka0e17fd72016-11-18 18:02:4633using google::protobuf::OneofDescriptor;
Vitaly Buka2cfe02b2016-11-19 00:34:0934using google::protobuf::Reflection;
Vitaly Buka0e17fd72016-11-18 18:02:4635
Vitaly Buka432b5452016-12-09 22:42:0936namespace protobuf_mutator {
37
Vitaly Buka0e17fd72016-11-18 18:02:4638namespace {
39
Vitaly Buka72019dc2016-12-15 03:17:2440const size_t kMaxInitializeDepth = 32;
41const size_t kDeletionThreshold = 128;
42const uint64_t kMutateWeight = 1000000;
Vitaly Buka0e17fd72016-11-18 18:02:4643
44enum class Mutation {
Vitaly Buka30de3092016-11-18 19:39:0745 None,
Vitaly Buka4af611d2016-12-04 02:57:3246 Add, // Adds new field with default value.
47 Mutate, // Mutates field contents.
48 Delete, // Deletes field.
Vitaly Bukaa3e59c72016-12-07 00:53:5649 Copy, // Copy values copied from another field.
Vitaly Buka4af611d2016-12-04 02:57:3250
Vitaly Buka432b5452016-12-09 22:42:0951 // TODO(vitalybuka):
52 // Clone, // Adds new field with value copied from another field.
Vitaly Buka0e17fd72016-11-18 18:02:4653};
54
Vitaly Buka4af611d2016-12-04 02:57:3255// Flips random bit in the buffer.
56void FlipBit(size_t size, uint8_t* bytes,
57 ProtobufMutator::RandomEngine* random) {
58 size_t bit = std::uniform_int_distribution<size_t>(0, size * 8 - 1)(*random);
59 bytes[bit / 8] ^= (1u << (bit % 8));
60}
Vitaly Buka781853c2016-11-22 07:09:3561
Vitaly Buka4af611d2016-12-04 02:57:3262// Flips random bit in the value.
63template <class T>
64T FlipBit(T value, ProtobufMutator::RandomEngine* random) {
65 FlipBit(sizeof(value), reinterpret_cast<uint8_t*>(&value), random);
66 return value;
67}
Vitaly Buka781853c2016-11-22 07:09:3568
Vitaly Buka4af611d2016-12-04 02:57:3269// Return random integer from [0, count)
Vitaly Buka781853c2016-11-22 07:09:3570size_t GetRandomIndex(ProtobufMutator::RandomEngine* random, size_t count) {
71 assert(count > 0);
Vitaly Bukabec52222016-12-09 22:29:3272 if (count == 1) return 0;
Vitaly Buka781853c2016-11-22 07:09:3573 return std::uniform_int_distribution<size_t>(0, count - 1)(*random);
74}
Vitaly Buka0e17fd72016-11-18 18:02:4675
Vitaly Buka91ad7b02016-12-12 23:41:4176struct CreateDefaultFieldTransformation {
77 template <class T>
78 void Apply(const FieldInstance& field) const {
79 T value;
80 field.GetDefault(&value);
81 field.Create(value);
Vitaly Bukabec52222016-12-09 22:29:3282 }
Vitaly Buka91ad7b02016-12-12 23:41:4183};
Vitaly Bukabec52222016-12-09 22:29:3284
Vitaly Buka91ad7b02016-12-12 23:41:4185struct DeleteFieldTransformation {
86 template <class T>
87 void Apply(const FieldInstance& field) const {
88 field.Delete();
Vitaly Bukabec52222016-12-09 22:29:3289 }
Vitaly Bukabec52222016-12-09 22:29:3290};
91
Vitaly Bukaa3e59c72016-12-07 00:53:5692struct CopyFieldTransformation {
Vitaly Buka72019dc2016-12-15 03:17:2493 explicit CopyFieldTransformation(const FieldInstance& field)
94 : source(field) {}
Vitaly Bukaa3e59c72016-12-07 00:53:5695
96 template <class T>
Vitaly Buka72019dc2016-12-15 03:17:2497 void Apply(const FieldInstance& field) const {
Vitaly Bukaa3e59c72016-12-07 00:53:5698 T value;
99 source.Load(&value);
100 field.Store(value);
101 }
102
Vitaly Buka72019dc2016-12-15 03:17:24103 FieldInstance source;
Vitaly Bukaa3e59c72016-12-07 00:53:56104};
105
Vitaly Buka4af611d2016-12-04 02:57:32106// Selects random field and mutation from the given proto message.
Vitaly Buka781853c2016-11-22 07:09:35107class MutationSampler {
Vitaly Bukac9d22482016-11-21 21:29:17108 public:
Vitaly Buka72019dc2016-12-15 03:17:24109 MutationSampler(bool keep_initialized, size_t size_increase_hint,
Vitaly Buka781853c2016-11-22 07:09:35110 ProtobufMutator::RandomEngine* random, Message* message)
Vitaly Buka4af611d2016-12-04 02:57:32111 : keep_initialized_(keep_initialized), random_(random), sampler_(random) {
Vitaly Buka72019dc2016-12-15 03:17:24112 if (size_increase_hint < kDeletionThreshold) {
Vitaly Buka4af611d2016-12-04 02:57:32113 // Avoid adding new field and prefer deleting fields if we getting close
114 // to the limit.
Vitaly Buka72019dc2016-12-15 03:17:24115 float adjustment = 0.5 * size_increase_hint / kDeletionThreshold;
116 add_weight_ *= adjustment;
117 delete_weight_ *= 1 - adjustment;
Vitaly Buka781853c2016-11-22 07:09:35118 }
119 Sample(message);
Vitaly Bukabec52222016-12-09 22:29:32120 assert(mutation() != Mutation::None);
Vitaly Bukac9d22482016-11-21 21:29:17121 }
122
Vitaly Buka4af611d2016-12-04 02:57:32123 // Returns selected field.
Vitaly Bukabec52222016-12-09 22:29:32124 const FieldInstance& field() const { return sampler_.selected().field; }
Vitaly Buka4af611d2016-12-04 02:57:32125
126 // Returns selected mutation.
Vitaly Buka432b5452016-12-09 22:42:09127 Mutation mutation() const { return sampler_.selected().mutation; }
Vitaly Buka4af611d2016-12-04 02:57:32128
129 private:
Vitaly Buka781853c2016-11-22 07:09:35130 void Sample(Message* message) {
131 const Descriptor* descriptor = message->GetDescriptor();
132 const Reflection* reflection = message->GetReflection();
133
134 int field_count = descriptor->field_count();
135 for (int i = 0; i < field_count; ++i) {
136 const FieldDescriptor* field = descriptor->field(i);
137 if (const OneofDescriptor* oneof = field->containing_oneof()) {
138 // Handle entire oneof group on the first field.
139 if (field->index_in_oneof() == 0) {
Vitaly Buka4af611d2016-12-04 02:57:32140 sampler_.Try(
141 add_weight_,
Vitaly Bukabec52222016-12-09 22:29:32142 {{message,
143 oneof->field(GetRandomIndex(random_, oneof->field_count()))},
Vitaly Buka4af611d2016-12-04 02:57:32144 Mutation::Add});
Vitaly Buka781853c2016-11-22 07:09:35145 if (const FieldDescriptor* field =
146 reflection->GetOneofFieldDescriptor(*message, oneof)) {
Vitaly Buka4af611d2016-12-04 02:57:32147 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
Vitaly Bukabec52222016-12-09 22:29:32148 sampler_.Try(kMutateWeight, {{message, field}, Mutation::Mutate});
149 sampler_.Try(delete_weight_, {{message, field}, Mutation::Delete});
Vitaly Buka72019dc2016-12-15 03:17:24150 sampler_.Try(GetCopyWeight(field),
151 {{message, field}, Mutation::Copy});
Vitaly Buka781853c2016-11-22 07:09:35152 }
153 }
154 } else {
155 if (field->is_repeated()) {
Vitaly Bukabec52222016-12-09 22:29:32156 int field_size = reflection->FieldSize(*message, field);
157 sampler_.Try(add_weight_, {{message, field,
158 GetRandomIndex(random_, field_size + 1)},
159 Mutation::Add});
Vitaly Buka781853c2016-11-22 07:09:35160
Vitaly Bukabec52222016-12-09 22:29:32161 if (field_size) {
162 size_t random_index = GetRandomIndex(random_, field_size);
Vitaly Buka4af611d2016-12-04 02:57:32163 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
Vitaly Bukabec52222016-12-09 22:29:32164 sampler_.Try(kMutateWeight,
165 {{message, field, random_index}, Mutation::Mutate});
166 sampler_.Try(delete_weight_,
167 {{message, field, random_index}, Mutation::Delete});
Vitaly Buka72019dc2016-12-15 03:17:24168 sampler_.Try(GetCopyWeight(field),
Vitaly Bukaa3e59c72016-12-07 00:53:56169 {{message, field, random_index}, Mutation::Copy});
Vitaly Buka781853c2016-11-22 07:09:35170 }
171 } else {
172 if (reflection->HasField(*message, field)) {
Vitaly Buka4af611d2016-12-04 02:57:32173 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
Vitaly Bukabec52222016-12-09 22:29:32174 sampler_.Try(kMutateWeight, {{message, field}, Mutation::Mutate});
Vitaly Buka4af611d2016-12-04 02:57:32175 if ((!field->is_required() || !keep_initialized_))
Vitaly Bukabec52222016-12-09 22:29:32176 sampler_.Try(delete_weight_,
177 {{message, field}, Mutation::Delete});
Vitaly Buka72019dc2016-12-15 03:17:24178 sampler_.Try(GetCopyWeight(field),
179 {{message, field}, Mutation::Copy});
Vitaly Buka781853c2016-11-22 07:09:35180 } else {
Vitaly Bukabec52222016-12-09 22:29:32181 sampler_.Try(add_weight_, {{message, field}, Mutation::Add});
Vitaly Buka781853c2016-11-22 07:09:35182 }
183 }
184 }
185
186 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
187 if (field->is_repeated()) {
188 const int field_size = reflection->FieldSize(*message, field);
189 for (int j = 0; j < field_size; ++j)
190 Sample(reflection->MutableRepeatedMessage(message, field, j));
191 } else if (reflection->HasField(*message, field)) {
192 Sample(reflection->MutableMessage(message, field));
193 }
194 }
195 }
196 }
197
Vitaly Buka72019dc2016-12-15 03:17:24198 uint64_t GetCopyWeight(const FieldDescriptor* field) const {
199 // Coping sub-messages can increase size significantly.
200 return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
201 ? add_weight_
202 : kMutateWeight;
203 }
204
Vitaly Buka781853c2016-11-22 07:09:35205 bool keep_initialized_ = false;
Vitaly Buka4af611d2016-12-04 02:57:32206
207 // Adding and deleting are intrusive and expensive mutations, we'd like to do
Vitaly Buka432b5452016-12-09 22:42:09208 // them less often than field mutations.
Vitaly Buka781853c2016-11-22 07:09:35209 uint64_t add_weight_ = kMutateWeight / 10;
210 uint64_t delete_weight_ = kMutateWeight / 10;
Vitaly Buka781853c2016-11-22 07:09:35211
Vitaly Buka4af611d2016-12-04 02:57:32212 ProtobufMutator::RandomEngine* random_;
213
214 struct Result {
Vitaly Buka91ad7b02016-12-12 23:41:41215 Result() = default;
Vitaly Bukabec52222016-12-09 22:29:32216 Result(const FieldInstance& f, Mutation m) : field(f), mutation(m) {}
Vitaly Buka91ad7b02016-12-12 23:41:41217
Vitaly Bukabec52222016-12-09 22:29:32218 FieldInstance field;
219 Mutation mutation = Mutation::None;
Vitaly Buka4af611d2016-12-04 02:57:32220 };
221 WeightedReservoirSampler<Result, ProtobufMutator::RandomEngine> sampler_;
Vitaly Bukac9d22482016-11-21 21:29:17222};
223
Vitaly Bukaa3e59c72016-12-07 00:53:56224// Selects random field of compatible type to use for clone mutations.
225class DataSourceSampler {
226 public:
Vitaly Buka72019dc2016-12-15 03:17:24227 DataSourceSampler(const FieldInstance& match,
228 ProtobufMutator::RandomEngine* random, Message* message)
Vitaly Bukaa3e59c72016-12-07 00:53:56229 : match_(match), random_(random), sampler_(random) {
230 Sample(message);
231 }
232
233 // Returns selected field.
Vitaly Buka72019dc2016-12-15 03:17:24234 const FieldInstance& field() const {
235 assert(!IsEmpty());
236 return sampler_.selected();
237 }
238
239 bool IsEmpty() const { return sampler_.IsEmpty(); }
Vitaly Bukaa3e59c72016-12-07 00:53:56240
241 private:
242 void Sample(Message* message) {
243 const Descriptor* descriptor = message->GetDescriptor();
244 const Reflection* reflection = message->GetReflection();
245
246 int field_count = descriptor->field_count();
247 for (int i = 0; i < field_count; ++i) {
248 const FieldDescriptor* field = descriptor->field(i);
249 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
250 if (field->is_repeated()) {
251 const int field_size = reflection->FieldSize(*message, field);
252 for (int j = 0; j < field_size; ++j) {
253 Sample(reflection->MutableRepeatedMessage(message, field, j));
254 }
255 } else if (reflection->HasField(*message, field)) {
256 Sample(reflection->MutableMessage(message, field));
257 }
258 }
259
260 if (field->cpp_type() != match_.cpp_type()) continue;
261 if (match_.cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
262 if (field->enum_type() != match_.enum_type()) continue;
263 } else if (match_.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
264 if (field->message_type() != match_.message_type()) continue;
265 }
266
267 // TODO(vitalybuka) : make sure that values are different
268 if (field->is_repeated()) {
269 if (int field_size = reflection->FieldSize(*message, field)) {
270 sampler_.Try(field_size,
271 {message, field, GetRandomIndex(random_, field_size)});
272 }
273 } else {
274 if (reflection->HasField(*message, field)) {
275 sampler_.Try(1, {message, field});
276 }
277 }
278 }
279 }
280
Vitaly Buka72019dc2016-12-15 03:17:24281 FieldInstance match_;
Vitaly Bukaa3e59c72016-12-07 00:53:56282 ProtobufMutator::RandomEngine* random_;
283
Vitaly Buka72019dc2016-12-15 03:17:24284 WeightedReservoirSampler<FieldInstance, ProtobufMutator::RandomEngine>
285 sampler_;
Vitaly Bukaa3e59c72016-12-07 00:53:56286};
287
Vitaly Buka0e17fd72016-11-18 18:02:46288} // namespace
289
Vitaly Buka91ad7b02016-12-12 23:41:41290class MutateTransformation {
Vitaly Buka432b5452016-12-09 22:42:09291 public:
Vitaly Buka91ad7b02016-12-12 23:41:41292 MutateTransformation(size_t allowed_growth, ProtobufMutator* mutator)
293 : allowed_growth_(allowed_growth), mutator_(mutator) {}
294
295 template <class T>
296 void Apply(const FieldInstance& field) const {
297 T value;
298 field.Load(&value);
299 Mutate(&value);
300 field.Store(value);
Vitaly Buka432b5452016-12-09 22:42:09301 }
Vitaly Buka00b61072016-10-19 23:22:51302
Vitaly Buka432b5452016-12-09 22:42:09303 private:
Vitaly Buka91ad7b02016-12-12 23:41:41304 void Mutate(int32_t* value) const { *value = mutator_->MutateInt32(*value); }
305
306 void Mutate(int64_t* value) const { *value = mutator_->MutateInt64(*value); }
307
308 void Mutate(uint32_t* value) const {
309 *value = mutator_->MutateUInt32(*value);
310 }
311
312 void Mutate(uint64_t* value) const {
313 *value = mutator_->MutateUInt64(*value);
314 }
315
316 void Mutate(float* value) const { *value = mutator_->MutateFloat(*value); }
317
318 void Mutate(double* value) const { *value = mutator_->MutateDouble(*value); }
319
320 void Mutate(bool* value) const { *value = mutator_->MutateBool(*value); }
321
322 void Mutate(FieldInstance::Enum* value) const {
323 value->index = mutator_->MutateEnum(value->index, value->count);
324 assert(value->index < value->count);
325 }
326
327 void Mutate(std::string* value) const {
328 *value = mutator_->MutateString(*value, allowed_growth_);
329 }
330
331 void Mutate(std::unique_ptr<Message>*) const { assert(!"Unexpected"); }
Vitaly Buka432b5452016-12-09 22:42:09332
333 size_t allowed_growth_;
334 ProtobufMutator* mutator_;
Vitaly Buka432b5452016-12-09 22:42:09335};
336
Vitaly Bukaba129722016-12-15 01:29:15337ProtobufMutator::ProtobufMutator(uint32_t seed) : random_(seed) {}
Vitaly Buka432b5452016-12-09 22:42:09338
Vitaly Buka72019dc2016-12-15 03:17:24339void ProtobufMutator::Mutate(Message* message, size_t size_increase_hint) {
340 MutationSampler mutation(keep_initialized_, size_increase_hint, &random_,
341 message);
Vitaly Buka781853c2016-11-22 07:09:35342 switch (mutation.mutation()) {
343 case Mutation::None:
344 break;
345 case Mutation::Add:
Vitaly Buka91ad7b02016-12-12 23:41:41346 mutation.field().Apply(CreateDefaultFieldTransformation());
Vitaly Buka781853c2016-11-22 07:09:35347 break;
348 case Mutation::Mutate:
Vitaly Buka72019dc2016-12-15 03:17:24349 mutation.field().Apply(
350 MutateTransformation(size_increase_hint / 4, this));
Vitaly Buka781853c2016-11-22 07:09:35351 break;
352 case Mutation::Delete:
Vitaly Buka91ad7b02016-12-12 23:41:41353 mutation.field().Apply(DeleteFieldTransformation());
Vitaly Buka781853c2016-11-22 07:09:35354 break;
Vitaly Bukaa3e59c72016-12-07 00:53:56355 case Mutation::Copy: {
356 DataSourceSampler source(mutation.field(), &random_, message);
Vitaly Buka72019dc2016-12-15 03:17:24357 if (source.IsEmpty()) {
Vitaly Bukaa3e59c72016-12-07 00:53:56358 // Fallback to message deletion.
359 mutation.field().Apply(DeleteFieldTransformation());
360 break;
361 }
Vitaly Bukaa3e59c72016-12-07 00:53:56362 mutation.field().Apply(CopyFieldTransformation(source.field()));
363 break;
364 }
Vitaly Buka781853c2016-11-22 07:09:35365 default:
366 assert(!"unexpected mutation");
Vitaly Buka0e17fd72016-11-18 18:02:46367 }
368
Vitaly Buka781853c2016-11-22 07:09:35369 if (keep_initialized_ && !message->IsInitialized()) {
370 InitializeMessage(message, kMaxInitializeDepth);
371 assert(message->IsInitialized());
Vitaly Buka0e17fd72016-11-18 18:02:46372 }
Vitaly Buka00b61072016-10-19 23:22:51373}
374
Vitaly Buka72019dc2016-12-15 03:17:24375void ProtobufMutator::InitializeMessage(Message* message, size_t max_depth) {
Vitaly Buka781853c2016-11-22 07:09:35376 assert(keep_initialized_);
Vitaly Buka432b5452016-12-09 22:42:09377 // It's pointless but possible to have infinite recursion of required
378 // messages.
379 assert(max_depth);
Vitaly Buka13245af2016-11-18 21:20:12380 const Descriptor* descriptor = message->GetDescriptor();
381 const Reflection* reflection = message->GetReflection();
Vitaly Buka13245af2016-11-18 21:20:12382 for (int i = 0; i < descriptor->field_count(); ++i) {
383 const FieldDescriptor* field = descriptor->field(i);
Vitaly Buka91ad7b02016-12-12 23:41:41384 if (field->is_required() && !reflection->HasField(*message, field))
385 FieldInstance(message, field).Apply(CreateDefaultFieldTransformation());
Vitaly Buka13245af2016-11-18 21:20:12386
Vitaly Buka781853c2016-11-22 07:09:35387 if (max_depth > 0 &&
388 field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
Vitaly Buka2cfe02b2016-11-19 00:34:09389 if (field->is_repeated()) {
390 const int field_size = reflection->FieldSize(*message, field);
391 for (int j = 0; j < field_size; ++j) {
392 Message* nested_message =
393 reflection->MutableRepeatedMessage(message, field, j);
Vitaly Buka781853c2016-11-22 07:09:35394 if (!nested_message->IsInitialized())
395 InitializeMessage(nested_message, max_depth - 1);
Vitaly Buka2cfe02b2016-11-19 00:34:09396 }
397 } else if (reflection->HasField(*message, field)) {
398 Message* nested_message = reflection->MutableMessage(message, field);
Vitaly Buka781853c2016-11-22 07:09:35399 if (!nested_message->IsInitialized())
400 InitializeMessage(nested_message, max_depth - 1);
Vitaly Buka13245af2016-11-18 21:20:12401 }
402 }
403 }
404}
Vitaly Buka4af611d2016-12-04 02:57:32405
406int32_t ProtobufMutator::MutateInt32(int32_t value) {
407 return FlipBit(value, &random_);
408}
409
410int64_t ProtobufMutator::MutateInt64(int64_t value) {
411 return FlipBit(value, &random_);
412}
413
414uint32_t ProtobufMutator::MutateUInt32(uint32_t value) {
415 return FlipBit(value, &random_);
416}
417
418uint64_t ProtobufMutator::MutateUInt64(uint64_t value) {
419 return FlipBit(value, &random_);
420}
421
422float ProtobufMutator::MutateFloat(float value) {
423 return FlipBit(value, &random_);
424}
425
426double ProtobufMutator::MutateDouble(double value) {
427 return FlipBit(value, &random_);
428}
429
430bool ProtobufMutator::MutateBool(bool value) {
431 return std::uniform_int_distribution<uint8_t>(0, 1)(random_);
432}
433
434size_t ProtobufMutator::MutateEnum(size_t index, size_t item_count) {
435 return (index +
436 std::uniform_int_distribution<uint8_t>(1, item_count - 1)(random_)) %
437 item_count;
438}
439
440std::string ProtobufMutator::MutateString(const std::string& value,
441 size_t allowed_growth) {
442 std::string result = value;
Vitaly Buka4af611d2016-12-04 02:57:32443 int min_diff = result.empty() ? 0 : -1;
444 int max_diff = allowed_growth ? 1 : 0;
445 int diff = std::uniform_int_distribution<int>(min_diff, max_diff)(random_);
Vitaly Buka432b5452016-12-09 22:42:09446 if (diff == -1) {
447 result.erase(GetRandomIndex(&random_, result.size()), 1);
448 return result;
449 }
450
451 if (diff == 1) {
452 size_t index = GetRandomIndex(&random_, result.size() + 1);
453 result.insert(result.begin() + index, '\0');
454 FlipBit(1, reinterpret_cast<uint8_t*>(&result[index]), &random_);
455 return result;
456 }
457
Vitaly Buka4af611d2016-12-04 02:57:32458 if (!result.empty())
459 FlipBit(result.size(), reinterpret_cast<uint8_t*>(&result[0]), &random_);
460 return result;
461}
Vitaly Buka432b5452016-12-09 22:42:09462
463} // namespace protobuf_mutator