// Copyright 2021 Code Intelligence GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.code_intelligence.jazzer.api; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Random; /** * A convenience wrapper turning the raw fuzzer input bytes into Java primitive types. * *

The methods defined by this interface behave similarly to {@link Random#nextInt()}, with all * returned values depending deterministically on the fuzzer input for the current run. */ public interface FuzzedDataProvider { /** * Consumes a {@code boolean} from the fuzzer input. * * @return a {@code boolean} */ boolean consumeBoolean(); /** * Consumes a {@code boolean} array from the fuzzer input. *

The array will usually have length {@code length}, but might be shorter if the fuzzer input * is not sufficiently long. * * @param maxLength the maximum length of the array * @return a {@code boolean} array of length at most {@code length} */ boolean[] consumeBooleans(int maxLength); /** * Consumes a {@code byte} from the fuzzer input. * * @return a {@code byte} */ byte consumeByte(); /** * Consumes a {@code byte} between {@code min} and {@code max} from the fuzzer input. * * @param min the inclusive lower bound on the returned value * @param max the inclusive upper bound on the returned value * @return a {@code byte} in the range {@code [min, max]} */ byte consumeByte(byte min, byte max); /** * Consumes a {@code byte} array from the fuzzer input. *

The array will usually have length {@code length}, but might be shorter if the fuzzer input * is not sufficiently long. * * @param maxLength the maximum length of the array * @return a {@code byte} array of length at most {@code length} */ byte[] consumeBytes(int maxLength); /** * Consumes the remaining fuzzer input as a {@code byte} array. *

Note: After calling this method, further calls to methods of this interface will * return fixed values only. * * @return a {@code byte} array */ byte[] consumeRemainingAsBytes(); /** * Consumes a {@code short} from the fuzzer input. * * @return a {@code short} */ short consumeShort(); /** * Consumes a {@code short} between {@code min} and {@code max} from the fuzzer input. * * @param min the inclusive lower bound on the returned value * @param max the inclusive upper bound on the returned value * @return a {@code short} in the range {@code [min, max]} */ short consumeShort(short min, short max); /** * Consumes a {@code short} array from the fuzzer input. *

The array will usually have length {@code length}, but might be shorter if the fuzzer input * is not sufficiently long. * * @param maxLength the maximum length of the array * @return a {@code short} array of length at most {@code length} */ short[] consumeShorts(int maxLength); /** * Consumes an {@code int} from the fuzzer input. * * @return an {@code int} */ int consumeInt(); /** * Consumes an {@code int} between {@code min} and {@code max} from the fuzzer input. * * @param min the inclusive lower bound on the returned value * @param max the inclusive upper bound on the returned value * @return an {@code int} in the range {@code [min, max]} */ int consumeInt(int min, int max); /** * Consumes an {@code int} array from the fuzzer input. *

The array will usually have length {@code length}, but might be shorter if the fuzzer input * is not sufficiently long. * * @param maxLength the maximum length of the array * @return an {@code int} array of length at most {@code length} */ int[] consumeInts(int maxLength); /** * Consumes a {@code long} from the fuzzer input. * * @return a {@code long} */ long consumeLong(); /** * Consumes a {@code long} between {@code min} and {@code max} from the fuzzer input. * * @param min the inclusive lower bound on the returned value * @param max the inclusive upper bound on the returned value * @return a {@code long} in the range @{code [min, max]} */ long consumeLong(long min, long max); /** * Consumes a {@code long} array from the fuzzer input. *

The array will usually have length {@code length}, but might be shorter if the fuzzer input * is not sufficiently long. * * @param maxLength the maximum length of the array * @return a {@code long} array of length at most {@code length} */ long[] consumeLongs(int maxLength); /** * Consumes a {@code float} from the fuzzer input. * * @return a {@code float} that may have a special value (e.g. a NaN or infinity) */ float consumeFloat(); /** * Consumes a regular {@code float} from the fuzzer input. * * @return a {@code float} that is not a special value (e.g. not a NaN or infinity) */ float consumeRegularFloat(); /** * Consumes a regular {@code float} between {@code min} and {@code max} from the fuzzer input. * * @return a {@code float} in the range {@code [min, max]} */ float consumeRegularFloat(float min, float max); /** * Consumes a {@code float} between 0.0 and 1.0 (inclusive) from the fuzzer input. * * @return a {@code float} in the range {@code [0.0, 1.0]} */ float consumeProbabilityFloat(); /** * Consumes a {@code double} from the fuzzer input. * * @return a {@code double} that may have a special value (e.g. a NaN or infinity) */ double consumeDouble(); /** * Consumes a regular {@code double} from the fuzzer input. * * @return a {@code double} that is not a special value (e.g. not a NaN or infinity) */ double consumeRegularDouble(); /** * Consumes a regular {@code double} between {@code min} and {@code max} from the fuzzer input. * * @return a {@code double} in the range {@code [min, max]} */ double consumeRegularDouble(double min, double max); /** * Consumes a {@code double} between 0.0 and 1.0 (inclusive) from the fuzzer input. * * @return a {@code double} in the range {@code [0.0, 1.0]} */ double consumeProbabilityDouble(); /** * Consumes a {@code char} from the fuzzer input. */ char consumeChar(); /** * Consumes a {@code char} between {@code min} and {@code max} from the fuzzer input. * * @param min the inclusive lower bound on the returned value * @param max the inclusive upper bound on the returned value * @return a {@code char} in the range {@code [min, max]} */ char consumeChar(char min, char max); /** * Consumes a {@code char} from the fuzzer input that is never a UTF-16 surrogate character. */ char consumeCharNoSurrogates(); /** * Consumes a {@link String} from the fuzzer input. *

The returned string may be of any length between 0 and {@code maxLength}, even if there is * more fuzzer input available. * * @param maxLength the maximum length of the string * @return a {@link String} of length between 0 and {@code maxLength} (inclusive) */ String consumeString(int maxLength); /** * Consumes the remaining fuzzer input as a {@link String}. *

Note: After calling this method, further calls to methods of this interface will * return fixed values only. * * @return a {@link String} */ String consumeRemainingAsString(); /** * Consumes an ASCII-only {@link String} from the fuzzer input. *

The returned string may be of any length between 0 and {@code maxLength}, even if there is * more fuzzer input available. * * @param maxLength the maximum length of the string * @return a {@link String} of length between 0 and {@code maxLength} (inclusive) that contains * only ASCII characters */ String consumeAsciiString(int maxLength); /** * Consumes the remaining fuzzer input as an ASCII-only {@link String}. *

Note: After calling this method, further calls to methods of this interface will * return fixed values only. * * @return a {@link String} that contains only ASCII characters */ String consumeRemainingAsAsciiString(); /** * Returns the number of unconsumed bytes in the fuzzer input. * * @return the number of unconsumed bytes in the fuzzer input */ int remainingBytes(); /** * Picks an element from {@code collection} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param collection the {@link Collection} to pick an element from. * @param the type of the collection element * @return an element from {@code collection} chosen based on the fuzzer input */ @SuppressWarnings("unchecked") default T pickValue(Collection collection) { int size = collection.size(); if (size == 0) { throw new IllegalArgumentException("collection is empty"); } if (collection instanceof List) { return ((List) collection).get(consumeInt(0, size - 1)); } else { return (T) pickValue(collection.toArray()); } } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @param the type of the array element * @return an element from {@code array} chosen based on the fuzzer input */ default T pickValue(T[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default boolean pickValue(boolean[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default byte pickValue(byte[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default short pickValue(short[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default int pickValue(int[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default long pickValue(long[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default double pickValue(double[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default float pickValue(float[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks an element from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @return an element from {@code array} chosen based on the fuzzer input */ default char pickValue(char[] array) { return array[consumeInt(0, array.length - 1)]; } /** * Picks {@code numOfElements} elements from {@code collection} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param collection the {@link Collection} to pick an element from. * @param numOfElements the number of elements to pick. * @param the type of the collection element * @return an array of size {@code numOfElements} from {@code collection} chosen based on the * fuzzer input */ default List pickValues(Collection collection, int numOfElements) { int size = collection.size(); if (size == 0) { throw new IllegalArgumentException("collection is empty"); } if (numOfElements > collection.size()) { throw new IllegalArgumentException("numOfElements exceeds collection.size()"); } List remainingElements = new ArrayList<>(collection); List pickedElements = new ArrayList<>(); for (int i = 0; i < numOfElements; i++) { T element = pickValue(remainingElements); pickedElements.add(element); remainingElements.remove(element); } return pickedElements; } /** * Picks {@code numOfElements} elements from {@code array} based on the fuzzer input. *

Note: The distribution of picks is not perfectly uniform. * * @param array the array to pick an element from. * @param numOfElements the number of elements to pick. * @param the type of the array element * @return an array of size {@code numOfElements} from {@code array} chosen based on the fuzzer * input */ default List pickValues(T[] array, int numOfElements) { return pickValues(Arrays.asList(array), numOfElements); } }