3636import com .code_intelligence .jazzer .mutation .support .RangeSupport .FloatRange ;
3737import com .code_intelligence .jazzer .mutation .support .RangeSupport .LongRange ;
3838import com .code_intelligence .jazzer .mutation .support .TypeHolder ;
39+ import com .code_intelligence .jazzer .mutation .support .ValuePoolSupport ;
40+ import java .io .ByteArrayInputStream ;
3941import java .io .DataInputStream ;
4042import java .io .DataOutputStream ;
4143import java .io .IOException ;
4244import java .lang .reflect .AnnotatedArrayType ;
4345import java .lang .reflect .AnnotatedType ;
4446import java .nio .ByteBuffer ;
47+ import java .util .Arrays ;
4548import java .util .Optional ;
4649import java .util .function .Function ;
4750import java .util .function .Predicate ;
51+ import java .util .stream .Stream ;
4852
4953final class PrimitiveArrayMutatorFactory implements MutatorFactory {
5054
@@ -81,6 +85,7 @@ public static final class PrimitiveArrayMutator<T> extends SerializingMutator<T>
8185 private final SerializingMutator <byte []> innerMutator ;
8286 private final Function <byte [], T > toPrimitive ;
8387 private final Function <T , byte []> toBytes ;
88+ private final T [] valuePool ;
8489
8590 @ SuppressWarnings ("unchecked" )
8691 public PrimitiveArrayMutator (AnnotatedType type ) {
@@ -93,6 +98,56 @@ public PrimitiveArrayMutator(AnnotatedType type) {
9398 (SerializingMutator <byte []>) LibFuzzerMutatorFactory .tryCreate (innerByteArray ).get ();
9499 toPrimitive = (Function <byte [], T >) makeBytesToPrimitiveArrayConverter (elementType );
95100 toBytes = (Function <T , byte []>) makePrimitiveArrayToBytesConverter (elementType );
101+ Optional <T []> valuePool = extractValuePool (type );
102+ this .valuePool = valuePool .orElse (null );
103+ System .out .println (
104+ "Created ValuePool with length: " + (this .valuePool == null ? 0 : this .valuePool .length ));
105+ }
106+
107+ public boolean getMutatedType (Object value ) {
108+ return value .getClass ().isArray ()
109+ && value .getClass ().getComponentType ().isPrimitive ()
110+ && value .getClass ().getComponentType () == elementType .getType ();
111+ }
112+
113+ public Optional <T []> extractValuePool (AnnotatedType type ) {
114+ return ValuePoolSupport .extractRawValues (type )
115+ .map (
116+ stream ->
117+ stream
118+ .flatMap (
119+ o -> {
120+ if (getMutatedType (o )) {
121+ return Stream .of (o );
122+ } else {
123+ return Stream .empty ();
124+ }
125+ })
126+ .distinct ()
127+ .map (o -> (T ) o )
128+ // use a round-trip from the inner mutator to see if length and range
129+ // constraints are met
130+ .filter (
131+ o -> {
132+ try {
133+ byte [] valueBytes = toBytes .apply (o );
134+ byte [] roundTrip =
135+ toBytes .apply (
136+ toPrimitive .apply (
137+ innerMutator .readExclusive (
138+ new DataInputStream (
139+ new ByteArrayInputStream (valueBytes )))));
140+ System .out .println (
141+ "ValuePool candidate original bytes length: "
142+ + valueBytes .length
143+ + ", roundTrip bytes length: "
144+ + roundTrip .length );
145+ return Arrays .equals (roundTrip , valueBytes );
146+ } catch (IOException e ) {
147+ return false ;
148+ }
149+ })
150+ .toArray (size -> (T []) Arrays .copyOf (new Object [0 ], size )));
96151 }
97152
98153 @ Override
@@ -128,6 +183,15 @@ public T init(PseudoRandom prng) {
128183
129184 @ Override
130185 public T mutate (T value , PseudoRandom prng ) {
186+ if (valuePool != null && valuePool .length > 0 ) {
187+ if (prng .choice ()) {
188+ return prng .pickIn (valuePool );
189+ } else {
190+ // 50% chance to mutate vs picking from the pool
191+ return (T )
192+ toPrimitive .apply (innerMutator .mutate (toBytes .apply (prng .pickIn (valuePool )), prng ));
193+ }
194+ }
131195 return (T ) toPrimitive .apply (innerMutator .mutate (toBytes .apply (value ), prng ));
132196 }
133197
0 commit comments