2424import com .code_intelligence .jazzer .mutation .api .MutatorFactory ;
2525import com .code_intelligence .jazzer .mutation .api .PseudoRandom ;
2626import com .code_intelligence .jazzer .mutation .api .SerializingMutator ;
27+ import com .code_intelligence .jazzer .mutation .combinator .SamplingUtils ;
28+ import com .code_intelligence .jazzer .mutation .combinator .SamplingUtils .WeightedValue ;
2729import com .code_intelligence .jazzer .mutation .mutator .libfuzzer .LibFuzzerMutate ;
2830import com .code_intelligence .jazzer .mutation .runtime .MutatorRuntime ;
31+ import com .code_intelligence .jazzer .mutation .support .DictionaryProviderSupport ;
2932import com .code_intelligence .jazzer .mutation .support .RangeSupport ;
3033import com .code_intelligence .jazzer .mutation .support .RangeSupport .LongRange ;
3134import com .google .errorprone .annotations .ForOverride ;
3437import java .io .IOException ;
3538import java .lang .reflect .AnnotatedType ;
3639import java .lang .reflect .ParameterizedType ;
40+ import java .util .ArrayList ;
41+ import java .util .List ;
3742import java .util .Optional ;
43+ import java .util .function .Function ;
3844import java .util .function .Predicate ;
3945import java .util .stream .LongStream ;
4046
@@ -49,7 +55,7 @@ public Optional<SerializingMutator<?>> tryCreate(
4955
5056 if (clazz == byte .class || clazz == Byte .class ) {
5157 return Optional .of (
52- new AbstractIntegralMutator <Byte >(type , Byte .MIN_VALUE , Byte .MAX_VALUE ) {
58+ new AbstractIntegralMutator <Byte >(runtime , type , Byte .MIN_VALUE , Byte .MAX_VALUE ) {
5359 @ Override
5460 protected long mutateWithLibFuzzer (long value ) {
5561 return LibFuzzerMutate .mutateDefault ((byte ) value , this , 0 );
@@ -82,7 +88,7 @@ public void write(Byte value, DataOutputStream out) throws IOException {
8288 });
8389 } else if (clazz == short .class || clazz == Short .class ) {
8490 return Optional .of (
85- new AbstractIntegralMutator <Short >(type , Short .MIN_VALUE , Short .MAX_VALUE ) {
91+ new AbstractIntegralMutator <Short >(runtime , type , Short .MIN_VALUE , Short .MAX_VALUE ) {
8692 @ Override
8793 protected long mutateWithLibFuzzer (long value ) {
8894 return LibFuzzerMutate .mutateDefault ((short ) value , this , 0 );
@@ -115,7 +121,8 @@ public void write(Short value, DataOutputStream out) throws IOException {
115121 });
116122 } else if (clazz == int .class || clazz == Integer .class ) {
117123 return Optional .of (
118- new AbstractIntegralMutator <Integer >(type , Integer .MIN_VALUE , Integer .MAX_VALUE ) {
124+ new AbstractIntegralMutator <Integer >(
125+ runtime , type , Integer .MIN_VALUE , Integer .MAX_VALUE ) {
119126 @ Override
120127 protected long mutateWithLibFuzzer (long value ) {
121128 return LibFuzzerMutate .mutateDefault ((int ) value , this , 0 );
@@ -148,7 +155,7 @@ public void write(Integer value, DataOutputStream out) throws IOException {
148155 });
149156 } else if (clazz == long .class || clazz == Long .class ) {
150157 return Optional .of (
151- new AbstractIntegralMutator <Long >(type , Long .MIN_VALUE , Long .MAX_VALUE ) {
158+ new AbstractIntegralMutator <Long >(runtime , type , Long .MIN_VALUE , Long .MAX_VALUE ) {
152159 @ Override
153160 protected long mutateWithLibFuzzer (long value ) {
154161 return LibFuzzerMutate .mutateDefault (value , this , 0 );
@@ -197,9 +204,14 @@ abstract static class AbstractIntegralMutator<T extends Number> extends Serializ
197204 private final int largestMutableBitNegative ;
198205 private final int largestMutableBitPositive ;
199206 private final long [] specialValues ;
207+ private final long [] dictionaryValues ;
208+ private final Function <PseudoRandom , MutationFunction > mutationFunctionSampler ;
200209
201210 AbstractIntegralMutator (
202- AnnotatedType type , long defaultMinValueForType , long defaultMaxValueForType ) {
211+ MutatorRuntime runtime ,
212+ AnnotatedType type ,
213+ long defaultMinValueForType ,
214+ long defaultMaxValueForType ) {
203215 LongRange resolved =
204216 RangeSupport .resolveIntegralRange (type , defaultMinValueForType , defaultMaxValueForType );
205217 long minValue = resolved .min ;
@@ -232,6 +244,50 @@ abstract static class AbstractIntegralMutator<T extends Number> extends Serializ
232244 largestMutableBitPositive = bitWidth (maxValue );
233245 }
234246 this .specialValues = collectSpecialValues (minValue , maxValue );
247+
248+ this .dictionaryValues =
249+ DictionaryProviderSupport .extractRawValues (runtime , type )
250+ .map (
251+ stream ->
252+ stream
253+ .filter (v -> v instanceof Number )
254+ .map (v -> ((Number ) v ).longValue ())
255+ .filter (v -> v >= minValue )
256+ .filter (v -> v <= maxValue )
257+ .sorted ()
258+ .mapToLong (Long ::longValue )
259+ .toArray ())
260+ .orElse (null );
261+ List <WeightedValue <MutationFunction >> f = new ArrayList <>();
262+ f .add (new WeightedValue <>(1.0 , MutationFunction .BIT_FLIP ));
263+ f .add (new WeightedValue <>(1.0 , MutationFunction .RANDOM_WALK ));
264+ f .add (new WeightedValue <>(1.0 , MutationFunction .RANDOM_VALUE ));
265+ f .add (new WeightedValue <>(1.0 , MutationFunction .LIBFUZZER ));
266+ if (dictionaryValues != null && dictionaryValues .length > 0 ) {
267+ // Since weights here are relative, we need to adjust the weight of user dictionary mutator
268+ // so that it is taken proportionate the inverse probability specified in the annotation.
269+ // Basically, we need to scale up the weight for pInv:
270+ // 1/p --- x?
271+ // 1- 1/p --- totalFuncWeights
272+ // x = (1/p * totalFuncWeights) / (1 - 1/p)
273+ // = totalFuncWeights / (p - 1)
274+ double totalFuncWeights = 0.0 ;
275+ for (WeightedValue <MutationFunction > wf : f ) {
276+ totalFuncWeights += wf .weight ;
277+ }
278+ int invProbability = DictionaryProviderSupport .extractFirstInvProbability (type );
279+ double perValueWeight = totalFuncWeights / (invProbability - 1 );
280+ f .add (new WeightedValue <>(perValueWeight , MutationFunction .DICTIONARY_VALUE ));
281+ }
282+ this .mutationFunctionSampler = SamplingUtils .weightedSampler (f );
283+ }
284+
285+ private enum MutationFunction {
286+ BIT_FLIP ,
287+ DICTIONARY_VALUE ,
288+ LIBFUZZER ,
289+ RANDOM_VALUE ,
290+ RANDOM_WALK ,
235291 }
236292
237293 private static long [] collectSpecialValues (long minValue , long maxValue ) {
@@ -263,20 +319,25 @@ protected final long mutateImpl(long value, PseudoRandom prng) {
263319 final long previousValue = value ;
264320 // Mutate in a loop to verify that we really mutated.
265321 do {
266- switch (prng . indexIn ( 4 )) {
267- case 0 :
322+ switch (mutationFunctionSampler . apply ( prng )) {
323+ case BIT_FLIP :
268324 value = bitFlip (value , prng );
269325 break ;
270- case 1 :
326+ case RANDOM_WALK :
271327 value = randomWalk (value , prng );
272328 break ;
273- case 2 :
329+ case RANDOM_VALUE :
274330 value = prng .closedRange (minValue , maxValue );
275331 break ;
276- case 3 :
332+ case LIBFUZZER :
277333 // TODO: Replace this with a structure-aware dictionary/TORC search similar to fuzztest.
278334 value = forceInRange (mutateWithLibFuzzer (value ));
279335 break ;
336+ case DICTIONARY_VALUE :
337+ value = dictionaryValues [prng .indexIn (dictionaryValues .length )];
338+ break ;
339+ default :
340+ throw new AssertionError ("Invalid mutation function." );
280341 }
281342 } while (value == previousValue );
282343 return value ;
0 commit comments