diff --git a/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java b/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java index b1f38b509..7b4b5444f 100644 --- a/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java +++ b/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java @@ -308,6 +308,9 @@ default T pickValue(Collection collection) { * @return an element from {@code array} chosen based on the fuzzer input */ default T pickValue(T[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -319,6 +322,9 @@ default T pickValue(T[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default boolean pickValue(boolean[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -330,6 +336,9 @@ default boolean pickValue(boolean[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default byte pickValue(byte[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -341,6 +350,9 @@ default byte pickValue(byte[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default short pickValue(short[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -352,6 +364,9 @@ default short pickValue(short[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default int pickValue(int[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -363,6 +378,9 @@ default int pickValue(int[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default long pickValue(long[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -374,6 +392,9 @@ default long pickValue(long[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default double pickValue(double[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -385,6 +406,9 @@ default double pickValue(double[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default float pickValue(float[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -396,6 +420,9 @@ default float pickValue(float[] array) { * @return an element from {@code array} chosen based on the fuzzer input */ default char pickValue(char[] array) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return array[consumeInt(0, array.length - 1)]; } @@ -439,6 +466,9 @@ default List pickValues(Collection collection, int numOfElements) { * input */ default List pickValues(T[] array, int numOfElements) { + if (array.length == 0) { + throw new IllegalArgumentException("array is empty"); + } return pickValues(Arrays.asList(array), numOfElements); } } diff --git a/src/main/java/com/code_intelligence/jazzer/driver/FuzzedDataProviderImpl.java b/src/main/java/com/code_intelligence/jazzer/driver/FuzzedDataProviderImpl.java index 08e5298b2..6c742c67a 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/FuzzedDataProviderImpl.java +++ b/src/main/java/com/code_intelligence/jazzer/driver/FuzzedDataProviderImpl.java @@ -196,6 +196,12 @@ public long consumeLong(long min, long max) { @Override public float consumeRegularFloat(float min, float max) { + if (!Float.isFinite(min)) { + throw new IllegalArgumentException("min must be a regular float"); + } + if (!Float.isFinite(max)) { + throw new IllegalArgumentException("max must be a regular float"); + } if (min > max) { throw new IllegalArgumentException( String.format("min must be <= max (got min: %f, max: %f)", min, max)); @@ -209,6 +215,12 @@ public float consumeRegularFloat(float min, float max) { @Override public double consumeRegularDouble(double min, double max) { + if (!Double.isFinite(min)) { + throw new IllegalArgumentException("min must be a regular double"); + } + if (!Double.isFinite(max)) { + throw new IllegalArgumentException("max must be a regular double"); + } if (min > max) { throw new IllegalArgumentException( String.format("min must be <= max (got min: %f, max: %f)", min, max)); diff --git a/src/main/native/com/code_intelligence/jazzer/driver/fuzzed_data_provider.cpp b/src/main/native/com/code_intelligence/jazzer/driver/fuzzed_data_provider.cpp index 7a2c0158e..869cf1a01 100644 --- a/src/main/native/com/code_intelligence/jazzer/driver/fuzzed_data_provider.cpp +++ b/src/main/native/com/code_intelligence/jazzer/driver/fuzzed_data_provider.cpp @@ -98,10 +98,13 @@ ConsumeIntegralArray(JNIEnv &env, jobject self, jint max_length) { const auto *dataPtr = reinterpret_cast(env.GetLongField(self, gDataPtrField)); jint remainingBytes = env.GetIntField(self, gRemainingBytesField); + uint64_t requested_bytes = sizeof(T) * max_length; + // requested_bytes may overflow a jint so cap it to remainingBytes which will + // definitely be within jint's range + uint64_t capped_bytes = + std::min(requested_bytes, static_cast(remainingBytes)); - jint max_num_bytes = - std::min(static_cast(sizeof(T)) * max_length, remainingBytes); - jsize actual_length = max_num_bytes / sizeof(T); + jsize actual_length = static_cast(capped_bytes) / sizeof(T); jint actual_num_bytes = sizeof(T) * actual_length; auto array = (env.*(JniArrayType::kNewArrayFunc))(actual_length); (env.*(JniArrayType::kSetArrayRegionFunc))( @@ -209,7 +212,11 @@ T JNICALL ConsumeFloatInRange(JNIEnv &env, jobject self, T min, T max) { } T probability = ConsumeProbability(env, self); - return result + range * probability; + result += range * probability; + + // extreme values can cause precision errors that make result > max + // clamp the value to max when that happens + return std::min(result, max); } template