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 ;
34+ import com .code_intelligence .jazzer .mutation .support .DictionaryProviderSupport ;
3035import com .code_intelligence .jazzer .mutation .support .TypeHolder ;
36+ import java .io .DataInputStream ;
37+ import java .io .DataOutputStream ;
38+ import java .io .IOException ;
3139import java .lang .reflect .AnnotatedType ;
3240import java .nio .charset .StandardCharsets ;
3341import java .util .Optional ;
3442import java .util .function .Predicate ;
43+ import java .util .stream .Stream ;
3544
3645final class StringMutatorFactory implements MutatorFactory {
3746 private static final int HEADER_MASK = 0b1100_0000;
@@ -176,7 +185,9 @@ public Optional<SerializingMutator<?>> tryCreate(
176185
177186 AnnotatedType innerByteArray =
178187 notNull (withLength (new TypeHolder <byte []>() {}.annotatedType (), min , max ));
179- return LibFuzzerMutatorFactory .tryCreate (innerByteArray );
188+ Optional <SerializingMutator <?>> innerMutator =
189+ LibFuzzerMutatorFactory .tryCreate (innerByteArray );
190+ return UserDictionaryMutatorWrapper .of (innerMutator , type , min , max );
180191 })
181192 .map (
182193 byteArrayMutator -> {
@@ -198,4 +209,98 @@ public Optional<SerializingMutator<?>> tryCreate(
198209 (Predicate <Debuggable > inCycle ) -> "String" );
199210 });
200211 }
212+
213+ private static final class UserDictionaryMutatorWrapper extends SerializingMutator <byte []> {
214+ private final byte [][] dictionaryValues ;
215+ private final SerializingMutator <byte []> basicMutator ;
216+ private final int pInv ;
217+
218+ public static Optional <SerializingMutator <?>> of (
219+ Optional <SerializingMutator <?>> mutator , AnnotatedType type , int minSize , int maxSize ) {
220+ if (!mutator .isPresent ()) {
221+ return Optional .empty ();
222+ }
223+ Optional <byte [][]> values = generateDictionaryValues (type , minSize , maxSize );
224+ if (!values .isPresent ()) {
225+ return mutator ;
226+ }
227+ return Optional .of (
228+ new UserDictionaryMutatorWrapper (
229+ (SerializingMutator <byte []>) mutator .get (),
230+ values .get (),
231+ extractFirstInvProbability (type )));
232+ }
233+
234+ public UserDictionaryMutatorWrapper (
235+ SerializingMutator <byte []> basicMutator , byte [][] dictionaryValues , int pInv ) {
236+ this .basicMutator = basicMutator ;
237+ this .dictionaryValues = dictionaryValues ;
238+ this .pInv = pInv ;
239+ }
240+
241+ public static Optional <byte [][]> generateDictionaryValues (
242+ AnnotatedType type , int minSize , int maxSize ) {
243+ return DictionaryProviderSupport .extractRawValues (type )
244+ .map (
245+ stream ->
246+ stream
247+ .flatMap (
248+ o -> {
249+ if (o instanceof String ) {
250+ return Stream .of (((String ) o ).getBytes (StandardCharsets .UTF_8 ));
251+ } else {
252+ return Stream .empty ();
253+ }
254+ })
255+ .filter (b -> b .length >= minSize && b .length <= maxSize )
256+ .distinct ()
257+ .toArray (byte [][]::new ));
258+ }
259+
260+ @ Override
261+ public String toDebugString (Predicate <Debuggable > isInCycle ) {
262+ return "String" ;
263+ }
264+
265+ @ Override
266+ public byte [] read (DataInputStream in ) throws IOException {
267+ return basicMutator .read (in );
268+ }
269+
270+ @ Override
271+ public void write (byte [] value , DataOutputStream out ) throws IOException {
272+ basicMutator .write (value , out );
273+ }
274+
275+ @ Override
276+ public byte [] detach (byte [] value ) {
277+ return basicMutator .detach (value );
278+ }
279+
280+ @ Override
281+ public byte [] init (PseudoRandom prng ) {
282+ if (prng .trueInOneOutOf (pInv )) {
283+ return prng .pickIn (dictionaryValues );
284+ }
285+ return basicMutator .init (prng );
286+ }
287+
288+ @ Override
289+ public byte [] mutate (byte [] value , PseudoRandom prng ) {
290+ if (prng .trueInOneOutOf (pInv )) {
291+ return prng .pickIn (dictionaryValues );
292+ }
293+ return basicMutator .mutate (value , prng );
294+ }
295+
296+ @ Override
297+ public byte [] crossOver (byte [] value , byte [] otherValue , PseudoRandom prng ) {
298+ return basicMutator .crossOver (value , otherValue , prng );
299+ }
300+
301+ @ Override
302+ public boolean hasFixedSize () {
303+ return false ;
304+ }
305+ }
201306}
0 commit comments