4343import java .lang .reflect .AnnotatedType ;
4444import java .nio .ByteBuffer ;
4545import java .util .Optional ;
46+ import java .util .function .BiFunction ;
4647import java .util .function .Function ;
4748import java .util .function .Predicate ;
4849
@@ -81,6 +82,7 @@ public static final class PrimitiveArrayMutator<T> extends SerializingMutator<T>
8182 private final SerializingMutator <byte []> innerMutator ;
8283 private final Function <byte [], T > toPrimitive ;
8384 private final Function <T , byte []> toBytes ;
85+ private final BiFunction <byte [], PseudoRandom , T > toPrimitiveAfterMutate ;
8486
8587 @ SuppressWarnings ("unchecked" )
8688 public PrimitiveArrayMutator (AnnotatedType type ) {
@@ -92,6 +94,8 @@ public PrimitiveArrayMutator(AnnotatedType type) {
9294 innerMutator =
9395 (SerializingMutator <byte []>) LibFuzzerMutatorFactory .tryCreate (innerByteArray ).get ();
9496 toPrimitive = (Function <byte [], T >) makeBytesToPrimitiveArrayConverter (elementType );
97+ toPrimitiveAfterMutate =
98+ (BiFunction <byte [], PseudoRandom , T >) makeBytesToPrimitiveArrayAfterMutate (elementType );
9599 toBytes = (Function <T , byte []>) makePrimitiveArrayToBytesConverter (elementType );
96100 }
97101
@@ -128,14 +132,13 @@ public T init(PseudoRandom prng) {
128132
129133 @ Override
130134 public T mutate (T value , PseudoRandom prng ) {
131- return ( T ) toPrimitive .apply (innerMutator .mutate (toBytes .apply (value ), prng ));
135+ return toPrimitiveAfterMutate .apply (innerMutator .mutate (toBytes .apply (value ), prng ), prng );
132136 }
133137
134138 @ Override
135139 public T crossOver (T value , T otherValue , PseudoRandom prng ) {
136- return (T )
137- toPrimitive .apply (
138- innerMutator .crossOver (toBytes .apply (value ), toBytes .apply (otherValue ), prng ));
140+ return toPrimitive .apply (
141+ innerMutator .crossOver (toBytes .apply (value ), toBytes .apply (otherValue ), prng ));
139142 }
140143
141144 private void extractRange (AnnotatedType type ) {
@@ -250,6 +253,29 @@ private static AnnotatedType convertWithLength(AnnotatedType type, AnnotatedType
250253 }
251254 }
252255
256+ // Randomly maps the byte array from libFuzzer directly onto char[] or converts each byte into a
257+ // 2 byte char. This helps in cases where a String is constructed out of char[] and libFuzzer
258+ // inserts CESU8 encoded bytes into the byte[].
259+ public char [] postMutateChars (byte [] bytes , PseudoRandom prng ) {
260+ if (prng .choice ()) {
261+ return (char []) toPrimitive .apply (bytes );
262+ } else {
263+ char [] chars = new char [bytes .length ];
264+ for (int i = 0 ; i < chars .length ; i ++) {
265+ chars [i ] = (char ) bytes [i ];
266+ }
267+ return chars ;
268+ }
269+ }
270+
271+ public BiFunction <byte [], PseudoRandom , ?> makeBytesToPrimitiveArrayAfterMutate (
272+ AnnotatedType type ) {
273+ if (type .getType ().getTypeName ().equals ("char" )) {
274+ return this ::postMutateChars ;
275+ }
276+ return (bytes , ignored ) -> makeBytesToPrimitiveArrayConverter (type ).apply (bytes );
277+ }
278+
253279 public static Function <?, byte []> makePrimitiveArrayToBytesConverter (AnnotatedType type ) {
254280 switch (type .getType ().getTypeName ()) {
255281 case "int" :
0 commit comments