diff options
Diffstat (limited to 'agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java')
-rw-r--r-- | agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java b/agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java new file mode 100644 index 00000000..b1f38b50 --- /dev/null +++ b/agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java @@ -0,0 +1,444 @@ +// 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. + * + * <p>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. + * <p>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. + * <p>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. + * <p><b>Note:</b> 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. + * <p>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. + * <p>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. + * <p>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. + * <p>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}. + * <p><b>Note:</b> 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. + * <p>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}. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> The distribution of picks is not perfectly uniform. + * + * @param collection the {@link Collection} to pick an element from. + * @param <T> the type of the collection element + * @return an element from {@code collection} chosen based on the fuzzer input + */ + @SuppressWarnings("unchecked") + default<T> T pickValue(Collection<T> collection) { + int size = collection.size(); + if (size == 0) { + throw new IllegalArgumentException("collection is empty"); + } + if (collection instanceof List<?>) { + return ((List<T>) collection).get(consumeInt(0, size - 1)); + } else { + return (T) pickValue(collection.toArray()); + } + } + + /** + * Picks an element from {@code array} based on the fuzzer input. + * <p><b>Note:</b> The distribution of picks is not perfectly uniform. + * + * @param array the array to pick an element from. + * @param <T> the type of the array element + * @return an element from {@code array} chosen based on the fuzzer input + */ + default<T> T pickValue(T[] array) { + return array[consumeInt(0, array.length - 1)]; + } + + /** + * Picks an element from {@code array} based on the fuzzer input. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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. + * <p><b>Note:</b> 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 <T> the type of the collection element + * @return an array of size {@code numOfElements} from {@code collection} chosen based on the + * fuzzer input + */ + default<T> List<T> pickValues(Collection<T> 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<T> remainingElements = new ArrayList<>(collection); + List<T> 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. + * <p><b>Note:</b> 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 <T> the type of the array element + * @return an array of size {@code numOfElements} from {@code array} chosen based on the fuzzer + * input + */ + default<T> List<T> pickValues(T[] array, int numOfElements) { + return pickValues(Arrays.asList(array), numOfElements); + } +} |