1717package com .code_intelligence .jazzer .mutation .mutator .lang ;
1818
1919import static com .code_intelligence .jazzer .mutation .combinator .MutatorCombinators .mutateThenMapToImmutable ;
20- import static com .code_intelligence .jazzer .mutation .support .TypeSupport .*;
20+ import static com .code_intelligence .jazzer .mutation .support .DictionaryProviderSupport .extractFirstInvProbability ;
21+ import static com .code_intelligence .jazzer .mutation .support .TypeSupport .findFirstParentIfClass ;
22+ import static com .code_intelligence .jazzer .mutation .support .TypeSupport .notNull ;
23+ import static com .code_intelligence .jazzer .mutation .support .TypeSupport .withLength ;
2124
2225import com .code_intelligence .jazzer .mutation .annotation .Ascii ;
2326import com .code_intelligence .jazzer .mutation .annotation .UrlSegment ;
2427import com .code_intelligence .jazzer .mutation .annotation .WithUtf8Length ;
2528import com .code_intelligence .jazzer .mutation .api .Debuggable ;
2629import com .code_intelligence .jazzer .mutation .api .ExtendedMutatorFactory ;
2730import com .code_intelligence .jazzer .mutation .api .MutatorFactory ;
31+ import com .code_intelligence .jazzer .mutation .api .PseudoRandom ;
2832import com .code_intelligence .jazzer .mutation .api .SerializingMutator ;
2933import com .code_intelligence .jazzer .mutation .mutator .libfuzzer .LibFuzzerMutatorFactory ;
3034import com .code_intelligence .jazzer .mutation .runtime .MutatorRuntime ;
35+ import com .code_intelligence .jazzer .mutation .support .DictionaryProviderSupport ;
3136import com .code_intelligence .jazzer .mutation .support .TypeHolder ;
37+ import java .io .DataInputStream ;
38+ import java .io .DataOutputStream ;
39+ import java .io .IOException ;
3240import java .lang .reflect .AnnotatedType ;
3341import java .nio .charset .StandardCharsets ;
3442import java .util .Optional ;
3543import java .util .function .Predicate ;
44+ import java .util .stream .Stream ;
3645
3746final class StringMutatorFactory implements MutatorFactory {
3847 private static final int HEADER_MASK = 0b1100_0000;
@@ -177,7 +186,9 @@ public Optional<SerializingMutator<?>> tryCreate(
177186
178187 AnnotatedType innerByteArray =
179188 notNull (withLength (new TypeHolder <byte []>() {}.annotatedType (), min , max ));
180- return LibFuzzerMutatorFactory .tryCreate (runtime , innerByteArray );
189+ Optional <SerializingMutator <?>> innerMutator =
190+ LibFuzzerMutatorFactory .tryCreate (runtime , innerByteArray );
191+ return UserDictionaryMutatorWrapper .of (runtime , innerMutator , type , min , max );
181192 })
182193 .map (
183194 byteArrayMutator -> {
@@ -199,4 +210,102 @@ public Optional<SerializingMutator<?>> tryCreate(
199210 (Predicate <Debuggable > inCycle ) -> "String" );
200211 });
201212 }
213+
214+ private static final class UserDictionaryMutatorWrapper extends SerializingMutator <byte []> {
215+ private final byte [][] dictionaryValues ;
216+ private final SerializingMutator <byte []> basicMutator ;
217+ private final int pInv ;
218+
219+ public static Optional <SerializingMutator <?>> of (
220+ MutatorRuntime runtime ,
221+ Optional <SerializingMutator <?>> mutator ,
222+ AnnotatedType type ,
223+ int minSize ,
224+ int maxSize ) {
225+ if (!mutator .isPresent ()) {
226+ return Optional .empty ();
227+ }
228+ SerializingMutator <byte []> castedMutator =
229+ mutator .map (m -> (SerializingMutator <byte []>) m ).get ();
230+ Optional <byte [][]> values = generateDictionaryValues (runtime , type , minSize , maxSize );
231+ if (!values .isPresent ()) {
232+ return mutator ;
233+ }
234+ return Optional .of (
235+ new UserDictionaryMutatorWrapper (
236+ castedMutator , values .get (), extractFirstInvProbability (type )));
237+ }
238+
239+ public UserDictionaryMutatorWrapper (
240+ SerializingMutator <byte []> basicMutator , byte [][] dictionaryValues , int pInv ) {
241+ this .basicMutator = basicMutator ;
242+ this .dictionaryValues = dictionaryValues ;
243+ this .pInv = pInv ;
244+ }
245+
246+ public static Optional <byte [][]> generateDictionaryValues (
247+ MutatorRuntime runtime , AnnotatedType type , int minSize , int maxSize ) {
248+ return DictionaryProviderSupport .extractRawValues (runtime , type )
249+ .map (
250+ stream ->
251+ stream
252+ .flatMap (
253+ o -> {
254+ if (o instanceof String ) {
255+ return Stream .of (((String ) o ).getBytes (StandardCharsets .UTF_8 ));
256+ } else {
257+ return Stream .empty ();
258+ }
259+ })
260+ .filter (b -> b .length >= minSize && b .length <= maxSize )
261+ .distinct ()
262+ .toArray (byte [][]::new ));
263+ }
264+
265+ @ Override
266+ public String toDebugString (Predicate <Debuggable > isInCycle ) {
267+ return "String" ;
268+ }
269+
270+ @ Override
271+ public byte [] read (DataInputStream in ) throws IOException {
272+ return basicMutator .read (in );
273+ }
274+
275+ @ Override
276+ public void write (byte [] value , DataOutputStream out ) throws IOException {
277+ basicMutator .write (value , out );
278+ }
279+
280+ @ Override
281+ public byte [] detach (byte [] value ) {
282+ return basicMutator .detach (value );
283+ }
284+
285+ @ Override
286+ public byte [] init (PseudoRandom prng ) {
287+ if (prng .trueInOneOutOf (pInv )) {
288+ return prng .pickIn (dictionaryValues );
289+ }
290+ return basicMutator .init (prng );
291+ }
292+
293+ @ Override
294+ public byte [] mutate (byte [] value , PseudoRandom prng ) {
295+ if (prng .trueInOneOutOf (pInv )) {
296+ return prng .pickIn (dictionaryValues );
297+ }
298+ return basicMutator .mutate (value , prng );
299+ }
300+
301+ @ Override
302+ public byte [] crossOver (byte [] value , byte [] otherValue , PseudoRandom prng ) {
303+ return basicMutator .crossOver (value , otherValue , prng );
304+ }
305+
306+ @ Override
307+ public boolean hasFixedSize () {
308+ return false ;
309+ }
310+ }
202311}
0 commit comments