1 /*
2 * Copyright 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ProtoFuzzerMutator.h"
18
19 using std::cerr;
20 using std::endl;
21
22 namespace android {
23 namespace vts {
24 namespace fuzzer {
25
26 // Creates an inital stub of mutation/random generation result.
VarInstanceStubFromSpec(const VarSpec & var_spec)27 static VarInstance VarInstanceStubFromSpec(const VarSpec &var_spec) {
28 VarInstance result{};
29 if (var_spec.has_type()) {
30 result.set_type(var_spec.type());
31 } else {
32 cerr << "VarInstance with no type field: " << var_spec.DebugString();
33 exit(1);
34 }
35 if (var_spec.has_name()) {
36 result.set_name(var_spec.name());
37 }
38 if (var_spec.has_predefined_type()) {
39 result.set_predefined_type(var_spec.predefined_type());
40 }
41 return result;
42 }
43
ArrayRandomGen(const VarSpec & var_spec)44 VarInstance ProtoFuzzerMutator::ArrayRandomGen(const VarSpec &var_spec) {
45 VarInstance result{VarInstanceStubFromSpec(var_spec)};
46 size_t vector_size = var_spec.vector_size();
47 result.set_vector_size(vector_size);
48 for (size_t i = 0; i < vector_size; ++i) {
49 *result.add_vector_value() = this->RandomGen(var_spec.vector_value(0));
50 }
51 return result;
52 }
53
ArrayMutate(const VarInstance & var_instance)54 VarInstance ProtoFuzzerMutator::ArrayMutate(const VarInstance &var_instance) {
55 VarInstance result{var_instance};
56 size_t vector_size = result.vector_size();
57 size_t idx = rand_(vector_size);
58 *result.mutable_vector_value(idx) = this->Mutate(result.vector_value(idx));
59 return result;
60 }
61
EnumRandomGen(const VarSpec & var_spec)62 VarInstance ProtoFuzzerMutator::EnumRandomGen(const VarSpec &var_spec) {
63 VarInstance result{VarInstanceStubFromSpec(var_spec)};
64 const EnumData &blueprint =
65 FindPredefinedType(result.predefined_type()).enum_value();
66
67 size_t size = blueprint.enumerator_size();
68 size_t idx = rand_(size);
69
70 ScalarData scalar_value = blueprint.scalar_value(idx);
71 string scalar_type = blueprint.scalar_type();
72
73 // Mutate this enum like a scalar with probability
74 // odds_for/(odds_for + odds_against).
75 uint64_t odds_for = (this->mutator_config_).enum_bias_.first;
76 uint64_t odds_against = (this->mutator_config_).enum_bias_.second;
77 uint64_t rand_num = rand_(odds_for + odds_against);
78 if (rand_num < odds_for) {
79 scalar_value = Mutate(scalar_value, scalar_type);
80 }
81
82 *(result.mutable_scalar_value()) = scalar_value;
83 result.set_scalar_type(scalar_type);
84 return result;
85 }
86
EnumMutate(const VarInstance & var_instance)87 VarInstance ProtoFuzzerMutator::EnumMutate(const VarInstance &var_instance) {
88 // For TYPE_ENUM, VarInstance contains superset info of VarSpec.
89 return RandomGen(var_instance);
90 }
91
ScalarRandomGen(const VarSpec & var_spec)92 VarInstance ProtoFuzzerMutator::ScalarRandomGen(const VarSpec &var_spec) {
93 VarInstance result{VarInstanceStubFromSpec(var_spec)};
94 (*result.mutable_scalar_value()) =
95 RandomGen(var_spec.scalar_value(), var_spec.scalar_type());
96 return result;
97 }
98
ScalarMutate(const VarInstance & var_instance)99 VarInstance ProtoFuzzerMutator::ScalarMutate(const VarInstance &var_instance) {
100 VarInstance result{var_instance};
101 (*result.mutable_scalar_value()) =
102 Mutate(result.scalar_value(), result.scalar_type());
103 return result;
104 }
105
StructRandomGen(const VarSpec & var_spec)106 VarInstance ProtoFuzzerMutator::StructRandomGen(const VarSpec &var_spec) {
107 VarInstance result{VarInstanceStubFromSpec(var_spec)};
108 const TypeSpec &blueprint = FindPredefinedType(result.predefined_type());
109 for (const VarSpec &struct_value : blueprint.struct_value()) {
110 *result.add_struct_value() = this->RandomGen(struct_value);
111 }
112 return result;
113 }
114
StructMutate(const VarInstance & var_instance)115 VarInstance ProtoFuzzerMutator::StructMutate(const VarInstance &var_instance) {
116 VarInstance result{var_instance};
117 size_t size = result.struct_value_size();
118 size_t idx = rand_(size);
119 *result.mutable_struct_value(idx) = this->Mutate(result.struct_value(idx));
120 return result;
121 }
122
UnionRandomGen(const VarSpec & var_spec)123 VarInstance ProtoFuzzerMutator::UnionRandomGen(const VarSpec &var_spec) {
124 VarInstance result{VarInstanceStubFromSpec(var_spec)};
125 const TypeSpec &blueprint = FindPredefinedType(result.predefined_type());
126 size_t size = blueprint.union_value_size();
127 for (size_t i = 0; i < size; ++i) {
128 result.add_union_value();
129 }
130 size_t idx = rand_(size);
131 *result.mutable_union_value(idx) =
132 this->RandomGen(blueprint.union_value(idx));
133 return result;
134 }
135
UnionMutate(const VarInstance & var_instance)136 VarInstance ProtoFuzzerMutator::UnionMutate(const VarInstance &var_instance) {
137 VarInstance result{var_instance};
138 size_t size = result.union_value_size();
139 for (size_t i = 0; i < size; ++i) {
140 if (result.union_value(i).has_name()) {
141 *result.mutable_union_value(i) = this->Mutate(result.union_value(i));
142 }
143 }
144 return result;
145 }
146
VectorRandomGen(const VarSpec & var_spec)147 VarInstance ProtoFuzzerMutator::VectorRandomGen(const VarSpec &var_spec) {
148 VarInstance result{VarInstanceStubFromSpec(var_spec)};
149 size_t size = mutator_config_.default_vector_size_;
150 for (size_t i = 0; i < size; ++i) {
151 *result.add_vector_value() = this->RandomGen(var_spec.vector_value(0));
152 }
153 return result;
154 }
155
VectorMutate(const VarInstance & var_instance)156 VarInstance ProtoFuzzerMutator::VectorMutate(const VarInstance &var_instance) {
157 VarInstance result{var_instance};
158 size_t size = result.vector_size();
159 size_t idx = rand_(size);
160 *result.mutable_vector_value(idx) = this->Mutate(result.vector_value(idx));
161 return result;
162 }
163
RandomGen(const ScalarData & scalar_value,const string & scalar_type)164 ScalarData ProtoFuzzerMutator::RandomGen(const ScalarData &scalar_value,
165 const string &scalar_type) {
166 ScalarData result{};
167
168 if (scalar_type == "bool_t") {
169 result.set_bool_t(RandomGen(static_cast<bool>(scalar_value.bool_t())));
170 } else if (scalar_type == "int8_t") {
171 result.set_int8_t(RandomGen(scalar_value.int8_t()));
172 } else if (scalar_type == "uint8_t") {
173 result.set_uint8_t(RandomGen(scalar_value.uint8_t()));
174 } else if (scalar_type == "int16_t") {
175 result.set_int16_t(RandomGen(scalar_value.int16_t()));
176 } else if (scalar_type == "uint16_t") {
177 result.set_uint16_t(RandomGen(scalar_value.uint16_t()));
178 } else if (scalar_type == "int32_t") {
179 result.set_int32_t(RandomGen(scalar_value.int32_t()));
180 } else if (scalar_type == "uint32_t") {
181 result.set_uint32_t(RandomGen(scalar_value.uint32_t()));
182 } else if (scalar_type == "int64_t") {
183 result.set_int64_t(RandomGen(scalar_value.int64_t()));
184 } else if (scalar_type == "uint64_t") {
185 result.set_uint64_t(RandomGen(scalar_value.uint64_t()));
186 } else if (scalar_type == "float_t") {
187 result.set_float_t(RandomGen(scalar_value.float_t()));
188 } else if (scalar_type == "double_t") {
189 result.set_double_t(RandomGen(scalar_value.double_t()));
190 } else {
191 cout << scalar_type << " not supported.\n";
192 }
193
194 return result;
195 }
196
Mutate(const ScalarData & scalar_value,const string & scalar_type)197 ScalarData ProtoFuzzerMutator::Mutate(const ScalarData &scalar_value,
198 const string &scalar_type) {
199 ScalarData result{};
200
201 if (scalar_type == "bool_t") {
202 result.set_bool_t(Mutate(static_cast<bool>(scalar_value.bool_t())));
203 } else if (scalar_type == "int8_t") {
204 result.set_int8_t(Mutate(scalar_value.int8_t()));
205 } else if (scalar_type == "uint8_t") {
206 result.set_uint8_t(Mutate(scalar_value.uint8_t()));
207 } else if (scalar_type == "int16_t") {
208 result.set_int16_t(Mutate(scalar_value.int16_t()));
209 } else if (scalar_type == "uint16_t") {
210 result.set_uint16_t(Mutate(scalar_value.uint16_t()));
211 } else if (scalar_type == "int32_t") {
212 result.set_int32_t(Mutate(scalar_value.int32_t()));
213 } else if (scalar_type == "uint32_t") {
214 result.set_uint32_t(Mutate(scalar_value.uint32_t()));
215 } else if (scalar_type == "int64_t") {
216 result.set_int64_t(Mutate(scalar_value.int64_t()));
217 } else if (scalar_type == "uint64_t") {
218 result.set_uint64_t(Mutate(scalar_value.uint64_t()));
219 } else if (scalar_type == "float_t") {
220 result.set_float_t(Mutate(scalar_value.float_t()));
221 } else if (scalar_type == "double_t") {
222 result.set_double_t(Mutate(scalar_value.double_t()));
223 } else {
224 cout << scalar_type << " not supported.\n";
225 }
226
227 return result;
228 }
229
230 template <typename T>
RandomGen(T value)231 T ProtoFuzzerMutator::RandomGen(T value) {
232 // Generate a biased random scalar.
233 uint64_t rand_int = mutator_config_.scalar_bias_(rand_);
234
235 T result;
236 memcpy(&result, &rand_int, sizeof(T));
237 return result;
238 }
239
RandomGen(bool value)240 bool ProtoFuzzerMutator::RandomGen(bool value) {
241 return static_cast<bool>(rand_(2));
242 }
243
244 template <typename T>
Mutate(T value)245 T ProtoFuzzerMutator::Mutate(T value) {
246 size_t num_bits = 8 * sizeof(T);
247 T mask = static_cast<T>(1) << rand_(num_bits);
248 return value ^ mask;
249 }
250
Mutate(bool value)251 bool ProtoFuzzerMutator::Mutate(bool value) {
252 return RandomGen(value);
253 }
254
Mutate(float value)255 float ProtoFuzzerMutator::Mutate(float value) {
256 uint32_t copy;
257 memcpy(©, &value, sizeof(float));
258 uint32_t mask = static_cast<uint32_t>(1) << rand_(32);
259 copy ^= mask;
260 memcpy(&value, ©, sizeof(float));
261 return value;
262 }
263
Mutate(double value)264 double ProtoFuzzerMutator::Mutate(double value) {
265 uint64_t copy;
266 memcpy(©, &value, sizeof(double));
267 uint64_t mask = static_cast<uint64_t>(1) << rand_(64);
268 copy ^= mask;
269 memcpy(&value, ©, sizeof(double));
270 return value;
271 }
272
273 } // namespace fuzzer
274 } // namespace vts
275 } // namespace android
276