1 // Copyright (c) 2019 Google LLC
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 "source/fuzz/fuzzer_context.h"
16
17 #include <cmath>
18
19 namespace spvtools {
20 namespace fuzz {
21
22 namespace {
23 // Default <minimum, maximum> pairs of probabilities for applying various
24 // transformations. All values are percentages. Keep them in alphabetical order.
25
26 const std::pair<uint32_t, uint32_t> kChanceOfAddingAccessChain = {5, 50};
27 const std::pair<uint32_t, uint32_t> kChanceOfAddingAnotherStructField = {20,
28 90};
29 const std::pair<uint32_t, uint32_t> kChanceOfAddingArrayOrStructType = {20, 90};
30 const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBlock = {20, 90};
31 const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBreak = {5, 80};
32 const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadContinue = {5, 80};
33 const std::pair<uint32_t, uint32_t> kChanceOfAddingGlobalVariable = {20, 90};
34 const std::pair<uint32_t, uint32_t> kChanceOfAddingLoad = {5, 50};
35 const std::pair<uint32_t, uint32_t> kChanceOfAddingLocalVariable = {20, 90};
36 const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
37 const std::pair<uint32_t, uint32_t> kChanceOfAddingNoContractionDecoration = {
38 5, 70};
39 const std::pair<uint32_t, uint32_t> kChanceOfAddingStore = {5, 50};
40 const std::pair<uint32_t, uint32_t> kChanceOfAddingVectorType = {20, 70};
41 const std::pair<uint32_t, uint32_t> kChanceOfAdjustingFunctionControl = {20,
42 70};
43 const std::pair<uint32_t, uint32_t> kChanceOfAdjustingLoopControl = {20, 90};
44 const std::pair<uint32_t, uint32_t> kChanceOfAdjustingMemoryOperandsMask = {20,
45 90};
46 const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
47 90};
48 const std::pair<uint32_t, uint32_t> kChanceOfCallingFunction = {1, 10};
49 const std::pair<uint32_t, uint32_t> kChanceOfChoosingStructTypeVsArrayType = {
50 20, 80};
51 const std::pair<uint32_t, uint32_t> kChanceOfConstructingComposite = {20, 50};
52 const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
53 const std::pair<uint32_t, uint32_t> kChanceOfDonatingAdditionalModule = {5, 50};
54 const std::pair<uint32_t, uint32_t> kChanceOfGoingDeeperWhenMakingAccessChain =
55 {50, 95};
56 const std::pair<uint32_t, uint32_t> kChanceOfMakingDonorLivesafe = {40, 60};
57 const std::pair<uint32_t, uint32_t> kChanceOfMergingBlocks = {20, 95};
58 const std::pair<uint32_t, uint32_t> kChanceOfMovingBlockDown = {20, 50};
59 const std::pair<uint32_t, uint32_t> kChanceOfObfuscatingConstant = {10, 90};
60 const std::pair<uint32_t, uint32_t> kChanceOfOutliningFunction = {10, 90};
61 const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
62 const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
63
64 // Default limits for various quantities that are chosen during fuzzing.
65 // Keep them in alphabetical order.
66 const uint32_t kDefaultMaxLoopControlPartialCount = 100;
67 const uint32_t kDefaultMaxLoopControlPeelCount = 100;
68 const uint32_t kDefaultMaxLoopLimit = 20;
69 const uint32_t kDefaultMaxNewArraySizeLimit = 100;
70
71 // Default functions for controlling how deep to go during recursive
72 // generation/transformation. Keep them in alphabetical order.
73
74 const std::function<bool(uint32_t, RandomGenerator*)>
75 kDefaultGoDeeperInConstantObfuscation =
__anonaff695220202(uint32_t current_depth, RandomGenerator* random_generator) 76 [](uint32_t current_depth, RandomGenerator* random_generator) -> bool {
77 double chance = 1.0 / std::pow(3.0, static_cast<float>(current_depth + 1));
78 return random_generator->RandomDouble() < chance;
79 };
80
81 } // namespace
82
FuzzerContext(RandomGenerator * random_generator,uint32_t min_fresh_id)83 FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
84 uint32_t min_fresh_id)
85 : random_generator_(random_generator),
86 next_fresh_id_(min_fresh_id),
87 max_loop_control_partial_count_(kDefaultMaxLoopControlPartialCount),
88 max_loop_control_peel_count_(kDefaultMaxLoopControlPeelCount),
89 max_loop_limit_(kDefaultMaxLoopLimit),
90 max_new_array_size_limit_(kDefaultMaxNewArraySizeLimit),
91 go_deeper_in_constant_obfuscation_(
92 kDefaultGoDeeperInConstantObfuscation) {
93 chance_of_adding_access_chain_ =
94 ChooseBetweenMinAndMax(kChanceOfAddingAccessChain);
95 chance_of_adding_another_struct_field_ =
96 ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField);
97 chance_of_adding_array_or_struct_type_ =
98 ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType);
99 chance_of_adding_dead_block_ =
100 ChooseBetweenMinAndMax(kChanceOfAddingDeadBlock);
101 chance_of_adding_dead_break_ =
102 ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
103 chance_of_adding_dead_continue_ =
104 ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
105 chance_of_adding_global_variable_ =
106 ChooseBetweenMinAndMax(kChanceOfAddingGlobalVariable);
107 chance_of_adding_load_ = ChooseBetweenMinAndMax(kChanceOfAddingLoad);
108 chance_of_adding_local_variable_ =
109 ChooseBetweenMinAndMax(kChanceOfAddingLocalVariable);
110 chance_of_adding_matrix_type_ =
111 ChooseBetweenMinAndMax(kChanceOfAddingMatrixType);
112 chance_of_adding_no_contraction_decoration_ =
113 ChooseBetweenMinAndMax(kChanceOfAddingNoContractionDecoration);
114 chance_of_adding_store_ = ChooseBetweenMinAndMax(kChanceOfAddingStore);
115 chance_of_adding_vector_type_ =
116 ChooseBetweenMinAndMax(kChanceOfAddingVectorType);
117 chance_of_adjusting_function_control_ =
118 ChooseBetweenMinAndMax(kChanceOfAdjustingFunctionControl);
119 chance_of_adjusting_loop_control_ =
120 ChooseBetweenMinAndMax(kChanceOfAdjustingLoopControl);
121 chance_of_adjusting_memory_operands_mask_ =
122 ChooseBetweenMinAndMax(kChanceOfAdjustingMemoryOperandsMask);
123 chance_of_adjusting_selection_control_ =
124 ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl);
125 chance_of_calling_function_ =
126 ChooseBetweenMinAndMax(kChanceOfCallingFunction);
127 chance_of_choosing_struct_type_vs_array_type_ =
128 ChooseBetweenMinAndMax(kChanceOfChoosingStructTypeVsArrayType);
129 chance_of_constructing_composite_ =
130 ChooseBetweenMinAndMax(kChanceOfConstructingComposite);
131 chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject);
132 chance_of_donating_additional_module_ =
133 ChooseBetweenMinAndMax(kChanceOfDonatingAdditionalModule);
134 chance_of_going_deeper_when_making_access_chain_ =
135 ChooseBetweenMinAndMax(kChanceOfGoingDeeperWhenMakingAccessChain);
136 chance_of_making_donor_livesafe_ =
137 ChooseBetweenMinAndMax(kChanceOfMakingDonorLivesafe);
138 chance_of_merging_blocks_ = ChooseBetweenMinAndMax(kChanceOfMergingBlocks);
139 chance_of_moving_block_down_ =
140 ChooseBetweenMinAndMax(kChanceOfMovingBlockDown);
141 chance_of_obfuscating_constant_ =
142 ChooseBetweenMinAndMax(kChanceOfObfuscatingConstant);
143 chance_of_outlining_function_ =
144 ChooseBetweenMinAndMax(kChanceOfOutliningFunction);
145 chance_of_replacing_id_with_synonym_ =
146 ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
147 chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
148 }
149
150 FuzzerContext::~FuzzerContext() = default;
151
GetFreshId()152 uint32_t FuzzerContext::GetFreshId() { return next_fresh_id_++; }
153
ChooseEven()154 bool FuzzerContext::ChooseEven() { return random_generator_->RandomBool(); }
155
ChoosePercentage(uint32_t percentage_chance)156 bool FuzzerContext::ChoosePercentage(uint32_t percentage_chance) {
157 assert(percentage_chance <= 100);
158 return random_generator_->RandomPercentage() < percentage_chance;
159 }
160
ChooseBetweenMinAndMax(const std::pair<uint32_t,uint32_t> & min_max)161 uint32_t FuzzerContext::ChooseBetweenMinAndMax(
162 const std::pair<uint32_t, uint32_t>& min_max) {
163 assert(min_max.first <= min_max.second);
164 return min_max.first +
165 random_generator_->RandomUint32(min_max.second - min_max.first + 1);
166 }
167
168 } // namespace fuzz
169 } // namespace spvtools
170