aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Meumertzheim <fabian@meumertzhe.im>2022-08-04 09:57:03 +0200
committerFabian Meumertzheim <fabian@meumertzhe.im>2022-08-10 12:50:59 +0200
commit5585339ca6a009d2e2507513b35f05682358f4ba (patch)
tree4a4fefbe35db542e602413d9ac5d59d32553cc50
parent678ceb53e8c2f045b550f3ddbd80ed7a9818de41 (diff)
downloadjazzer-api-5585339ca6a009d2e2507513b35f05682358f4ba.tar.gz
driver: Extract Java feed method out of FuzzedDataProvider
Simplifies the replayer and allows us to Javaify the FuzzedDataProvider test.
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/replay/BUILD.bazel3
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/replay/Replayer.java7
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java5
-rw-r--r--agent/src/main/native/com/code_intelligence/jazzer/replay/com_code_intelligence_jazzer_replay_Replayer.cpp46
-rw-r--r--agent/src/test/java/com/code_intelligence/jazzer/runtime/BUILD.bazel12
-rw-r--r--agent/src/test/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImplTest.java235
-rw-r--r--driver/BUILD.bazel11
-rw-r--r--driver/fuzzed_data_provider.cpp23
-rw-r--r--driver/fuzzed_data_provider_test.cpp120
-rw-r--r--driver/src/main/native/com/code_intelligence/jazzer/driver/BUILD.bazel (renamed from agent/src/main/native/com/code_intelligence/jazzer/replay/BUILD.bazel)9
-rw-r--r--driver/testdata/test/FuzzTargetWithDataProvider.java118
11 files changed, 283 insertions, 306 deletions
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/replay/BUILD.bazel b/agent/src/main/java/com/code_intelligence/jazzer/replay/BUILD.bazel
index df28adb4..08bd7653 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/replay/BUILD.bazel
+++ b/agent/src/main/java/com/code_intelligence/jazzer/replay/BUILD.bazel
@@ -3,8 +3,7 @@ load("@fmeum_rules_jni//jni:defs.bzl", "java_jni_library")
java_jni_library(
name = "replay",
srcs = ["Replayer.java"],
- native_libs = ["//agent/src/main/native/com/code_intelligence/jazzer/replay"],
- visibility = ["//agent/src/main/native/com/code_intelligence/jazzer/replay:__pkg__"],
+ native_libs = ["//driver/src/main/native/com/code_intelligence/jazzer/driver:fuzzed_data_provider_standalone"],
deps = [
"//agent/src/main/java/com/code_intelligence/jazzer/api",
"//agent/src/main/java/com/code_intelligence/jazzer/runtime:fuzzed_data_provider",
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/replay/Replayer.java b/agent/src/main/java/com/code_intelligence/jazzer/replay/Replayer.java
index fc6bfc4f..ae509dad 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/replay/Replayer.java
+++ b/agent/src/main/java/com/code_intelligence/jazzer/replay/Replayer.java
@@ -30,7 +30,8 @@ public class Replayer {
static {
try {
- RulesJni.loadLibrary("replay", Replayer.class);
+ RulesJni.loadLibrary(
+ "fuzzed_data_provider_standalone", "/com/code_intelligence/jazzer/driver");
} catch (Throwable t) {
t.printStackTrace();
System.exit(STATUS_OTHER_ERROR);
@@ -151,9 +152,7 @@ public class Replayer {
}
private static FuzzedDataProvider makeFuzzedDataProvider(byte[] input) {
- feedFuzzedDataProvider(input);
+ FuzzedDataProviderImpl.feed(input);
return new FuzzedDataProviderImpl();
}
-
- private static native void feedFuzzedDataProvider(byte[] input);
}
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java b/agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java
index 262e4596..4b8ec7f2 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java
+++ b/agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java
@@ -34,6 +34,11 @@ public class FuzzedDataProviderImpl implements FuzzedDataProvider {
// input.
public static native void reset();
+ // Feeds new raw fuzzer input into the provider.
+ // Note: Clients *must not* use this method if they also use the native FeedFuzzedDataProvider
+ // method.
+ public static native void feed(byte[] input);
+
@Override public native boolean consumeBoolean();
@Override public native boolean[] consumeBooleans(int maxLength);
diff --git a/agent/src/main/native/com/code_intelligence/jazzer/replay/com_code_intelligence_jazzer_replay_Replayer.cpp b/agent/src/main/native/com/code_intelligence/jazzer/replay/com_code_intelligence_jazzer_replay_Replayer.cpp
deleted file mode 100644
index e481e82f..00000000
--- a/agent/src/main/native/com/code_intelligence/jazzer/replay/com_code_intelligence_jazzer_replay_Replayer.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#include "com_code_intelligence_jazzer_replay_Replayer.h"
-
-#include <jni.h>
-
-#include "driver/fuzzed_data_provider.h"
-
-namespace {
-uint8_t *data = nullptr;
-}
-
-void Java_com_code_1intelligence_jazzer_replay_Replayer_feedFuzzedDataProvider(
- JNIEnv *env, jclass, jbyteArray input) {
- if (data != nullptr) {
- delete[] data;
- }
-
- std::size_t size = env->GetArrayLength(input);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->FatalError("Failed to get length of input");
- }
- data = static_cast<uint8_t *>(operator new(size));
- if (data == nullptr) {
- env->FatalError("Failed to allocate memory for a copy of the input");
- }
- env->GetByteArrayRegion(input, 0, size, reinterpret_cast<jbyte *>(data));
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->FatalError("Failed to copy input");
- }
- jazzer::FeedFuzzedDataProvider(data, size);
-}
diff --git a/agent/src/test/java/com/code_intelligence/jazzer/runtime/BUILD.bazel b/agent/src/test/java/com/code_intelligence/jazzer/runtime/BUILD.bazel
index ad7ddb01..4fa0df37 100644
--- a/agent/src/test/java/com/code_intelligence/jazzer/runtime/BUILD.bazel
+++ b/agent/src/test/java/com/code_intelligence/jazzer/runtime/BUILD.bazel
@@ -1,6 +1,18 @@
load("//bazel:compat.bzl", "SKIP_ON_WINDOWS")
java_test(
+ name = "FuzzedDataProviderImplTest",
+ srcs = ["FuzzedDataProviderImplTest.java"],
+ use_testrunner = False,
+ deps = [
+ "//agent/src/main/java/com/code_intelligence/jazzer/api",
+ "//agent/src/main/java/com/code_intelligence/jazzer/runtime:fuzzed_data_provider",
+ "//driver/src/main/native/com/code_intelligence/jazzer/driver:fuzzed_data_provider_standalone",
+ "@fmeum_rules_jni//jni/tools/native_loader",
+ ],
+)
+
+java_test(
name = "RecordingFuzzedDataProviderTest",
srcs = [
"RecordingFuzzedDataProviderTest.java",
diff --git a/agent/src/test/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImplTest.java b/agent/src/test/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImplTest.java
new file mode 100644
index 00000000..53f28d8b
--- /dev/null
+++ b/agent/src/test/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImplTest.java
@@ -0,0 +1,235 @@
+// 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.runtime;
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.github.fmeum.rules_jni.RulesJni;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+public class FuzzedDataProviderImplTest {
+ static {
+ try {
+ RulesJni.loadLibrary(
+ "fuzzed_data_provider_standalone", "/com/code_intelligence/jazzer/driver");
+ } catch (Throwable t) {
+ t.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ public static void main(String[] args) {
+ FuzzedDataProviderImpl fuzzedDataProvider = new FuzzedDataProviderImpl();
+ FuzzedDataProviderImpl.feed(INPUT_BYTES);
+ verifyFuzzedDataProvider(fuzzedDataProvider);
+ }
+
+ private strictfp static void verifyFuzzedDataProvider(FuzzedDataProvider data) {
+ assertEqual(true, data.consumeBoolean());
+
+ assertEqual((byte) 0x7F, data.consumeByte());
+ assertEqual((byte) 0x14, data.consumeByte((byte) 0x12, (byte) 0x22));
+
+ assertEqual(0x12345678, data.consumeInt());
+ assertEqual(-0x12345600, data.consumeInt(-0x12345678, -0x12345600));
+ assertEqual(0x12345679, data.consumeInt(0x12345678, 0x12345679));
+
+ assertEqual(true, Arrays.equals(new byte[] {0x01, 0x02}, data.consumeBytes(2)));
+
+ assertEqual("jazzer", data.consumeString(6));
+ assertEqual("ja\u0000zer", data.consumeString(6));
+ assertEqual("ۧ", data.consumeString(2));
+
+ assertEqual("jazzer", data.consumeAsciiString(6));
+ assertEqual("ja\u0000zer", data.consumeAsciiString(6));
+ assertEqual("\u0062\u0002\u002C\u0043\u001F", data.consumeAsciiString(5));
+
+ assertEqual(true,
+ Arrays.equals(new boolean[] {false, false, true, false, true}, data.consumeBooleans(5)));
+ assertEqual(true,
+ Arrays.equals(new long[] {0x0123456789abdcefL, 0xfedcba9876543210L}, data.consumeLongs(2)));
+
+ assertEqual((float) 0.28969181, data.consumeProbabilityFloat());
+ assertEqual(0.086814121166605432, data.consumeProbabilityDouble());
+ assertEqual((float) 0.30104411, data.consumeProbabilityFloat());
+ assertEqual(0.96218831486039413, data.consumeProbabilityDouble());
+
+ assertEqual((float) -2.8546307e+38, data.consumeRegularFloat());
+ assertEqual(8.0940194040236032e+307, data.consumeRegularDouble());
+ assertEqual((float) 271.49084, data.consumeRegularFloat((float) 123.0, (float) 777.0));
+ assertEqual(30.859126145478349, data.consumeRegularDouble(13.37, 31.337));
+
+ assertEqual((float) 0.0, data.consumeFloat());
+ assertEqual((float) -0.0, data.consumeFloat());
+ assertEqual(Float.POSITIVE_INFINITY, data.consumeFloat());
+ assertEqual(Float.NEGATIVE_INFINITY, data.consumeFloat());
+ assertEqual(true, Float.isNaN(data.consumeFloat()));
+ assertEqual(Float.MIN_VALUE, data.consumeFloat());
+ assertEqual(-Float.MIN_VALUE, data.consumeFloat());
+ assertEqual(Float.MIN_NORMAL, data.consumeFloat());
+ assertEqual(-Float.MIN_NORMAL, data.consumeFloat());
+ assertEqual(Float.MAX_VALUE, data.consumeFloat());
+ assertEqual(-Float.MAX_VALUE, data.consumeFloat());
+
+ assertEqual(0.0, data.consumeDouble());
+ assertEqual(-0.0, data.consumeDouble());
+ assertEqual(Double.POSITIVE_INFINITY, data.consumeDouble());
+ assertEqual(Double.NEGATIVE_INFINITY, data.consumeDouble());
+ assertEqual(true, Double.isNaN(data.consumeDouble()));
+ assertEqual(Double.MIN_VALUE, data.consumeDouble());
+ assertEqual(-Double.MIN_VALUE, data.consumeDouble());
+ assertEqual(Double.MIN_NORMAL, data.consumeDouble());
+ assertEqual(-Double.MIN_NORMAL, data.consumeDouble());
+ assertEqual(Double.MAX_VALUE, data.consumeDouble());
+ assertEqual(-Double.MAX_VALUE, data.consumeDouble());
+
+ int[] array = {0, 1, 2, 3, 4};
+ assertEqual(4, data.pickValue(array));
+ assertEqual(2, (int) data.pickValue(Arrays.stream(array).boxed().toArray()));
+ assertEqual(3, data.pickValue(Arrays.stream(array).boxed().collect(Collectors.toList())));
+ assertEqual(2, data.pickValue(Arrays.stream(array).boxed().collect(Collectors.toSet())));
+
+ // Buffer is almost depleted at this point.
+ assertEqual(7, data.remainingBytes());
+ assertEqual(true, Arrays.equals(new long[0], data.consumeLongs(3)));
+ assertEqual(7, data.remainingBytes());
+ assertEqual(true, Arrays.equals(new int[] {0x12345678}, data.consumeInts(3)));
+ assertEqual(3, data.remainingBytes());
+ assertEqual(0x123456L, data.consumeLong());
+
+ // Buffer has been fully consumed at this point
+ assertEqual(0, data.remainingBytes());
+ assertEqual(0, data.consumeInt());
+ assertEqual(0.0, data.consumeDouble());
+ assertEqual(-13.37, data.consumeRegularDouble(-13.37, 31.337));
+ assertEqual(true, Arrays.equals(new byte[0], data.consumeBytes(4)));
+ assertEqual(true, Arrays.equals(new long[0], data.consumeLongs(4)));
+ assertEqual("", data.consumeRemainingAsAsciiString());
+ assertEqual("", data.consumeRemainingAsString());
+ assertEqual("", data.consumeAsciiString(100));
+ assertEqual("", data.consumeString(100));
+ }
+
+ private static <T extends Comparable<T>> void assertEqual(T a, T b) {
+ if (a.compareTo(b) != 0) {
+ throw new IllegalArgumentException("Expected: " + a + ", got: " + b);
+ }
+ }
+
+ private static final byte[] INPUT_BYTES = new byte[] {
+ // Bytes read from the start
+ 0x01, 0x02, // consumeBytes(2): {0x01, 0x02}
+
+ 'j', 'a', 'z', 'z', 'e', 'r', // consumeString(6): "jazzer"
+ 'j', 'a', 0x00, 'z', 'e', 'r', // consumeString(6): "ja\u0000zer"
+ (byte) 0xE2, (byte) 0x82, (byte) 0xAC, (byte) 0xC3, (byte) 0x9F, // consumeString(2): "€ẞ"
+
+ 'j', 'a', 'z', 'z', 'e', 'r', // consumeAsciiString(6): "jazzer"
+ 'j', 'a', 0x00, 'z', 'e', 'r', // consumeAsciiString(6): "ja\u0000zer"
+ (byte) 0xE2, (byte) 0x82, (byte) 0xAC, (byte) 0xC3,
+ (byte) 0x9F, // consumeAsciiString(5): "\u0062\u0002\u002C\u0043\u001F"
+
+ 0, 0, 1, 0, 1, // consumeBooleans(5): { false, false, true, false, true }
+ (byte) 0xEF, (byte) 0xDC, (byte) 0xAB, (byte) 0x89, 0x67, 0x45, 0x23, 0x01, 0x10, 0x32, 0x54,
+ 0x76, (byte) 0x98, (byte) 0xBA, (byte) 0xDC, (byte) 0xFE,
+ // consumeLongs(2): { 0x0123456789ABCDEF, 0xFEDCBA9876543210 }
+
+ 0x78, 0x56, 0x34, 0x12, // consumeInts(3): { 0x12345678 }
+ 0x56, 0x34, 0x12, // consumeLong():
+
+ // Bytes read from the end
+ 0x02, 0x03, 0x02, 0x04, // 4x pickValue in array with five elements
+
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 10, // -max for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 9, // max for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 8, // -min for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 7, // min for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 6, // -denorm_min for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 5, // denorm_min for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 4, // NaN for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 3, // -infinity for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 2, // infinity for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 1, // -0.0 for next consumeDouble
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, 0x12, 0x34, 0x56,
+ 0x78, // consumed but unused by consumeDouble()
+ 0, // 0.0 for next consumeDouble
+
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 10, // -max for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 9, // max for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 8, // -min for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 7, // min for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 6, // -denorm_min for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 5, // denorm_min for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 4, // NaN for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 3, // -infinity for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 2, // infinity for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 1, // -0.0 for next consumeFloat
+ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, // consumed but unused by consumeFloat()
+ 0, // 0.0 for next consumeFloat
+
+ (byte) 0x88, (byte) 0xAB, 0x61, (byte) 0xCB, 0x32, (byte) 0xEB, 0x30, (byte) 0xF9,
+ // consumeDouble(13.37, 31.337): 30.859126145478349 (small range)
+ 0x51, (byte) 0xF6, 0x1F, 0x3A, // consumeFloat(123.0, 777.0): 271.49084 (small range)
+ 0x11, 0x4D, (byte) 0xFD, 0x54, (byte) 0xD6, 0x3D, 0x43, 0x73, 0x39,
+ // consumeRegularDouble(): 8.0940194040236032e+307
+ 0x16, (byte) 0xCF, 0x3D, 0x29, 0x4A, // consumeRegularFloat(): -2.8546307e+38
+
+ 0x61, (byte) 0xCB, 0x32, (byte) 0xEB, 0x30, (byte) 0xF9, 0x51, (byte) 0xF6,
+ // consumeProbabilityDouble(): 0.96218831486039413
+ 0x1F, 0x3A, 0x11, 0x4D, // consumeProbabilityFloat(): 0.30104411
+ (byte) 0xFD, 0x54, (byte) 0xD6, 0x3D, 0x43, 0x73, 0x39, 0x16,
+ // consumeProbabilityDouble(): 0.086814121166605432
+ (byte) 0xCF, 0x3D, 0x29, 0x4A, // consumeProbabilityFloat(): 0.28969181
+
+ 0x01, // consumeInt(0x12345678, 0x12345679): 0x12345679
+ 0x78, // consumeInt(-0x12345678, -0x12345600): -0x12345600
+ 0x78, 0x56, 0x34, 0x12, // consumeInt(): 0x12345678
+
+ 0x02, // consumeByte(0x12, 0x22): 0x14
+ 0x7F, // consumeByte(): 0x7F
+
+ 0x01, // consumeBool(): true
+ };
+}
diff --git a/driver/BUILD.bazel b/driver/BUILD.bazel
index 118e6598..f8be51cb 100644
--- a/driver/BUILD.bazel
+++ b/driver/BUILD.bazel
@@ -33,7 +33,6 @@ cc_library(
"fuzzed_data_provider.h",
],
visibility = [
- "//agent/src/main/native/com/code_intelligence/jazzer/replay:__pkg__",
"//driver/src/main/native/com/code_intelligence/jazzer/driver:__pkg__",
"//driver/src/test:__subpackages__",
],
@@ -338,18 +337,8 @@ cc_test(
"//driver/testdata:fuzz_target_mocks_deploy.jar",
],
includes = ["."],
- linkopts = select({
- "@platforms//os:windows": [],
- "//conditions:default": [
- # Needs to export symbols dynamically for JNI_OnLoad_jazzer_initialize
- # to be found by the JVM.
- "-rdynamic",
- ],
- }),
- linkstatic = True,
deps = [
":jvm_tooling_lib",
- ":sanitizer_symbols_for_tests",
":test_main",
"@bazel_tools//tools/cpp/runfiles",
"@googletest//:gtest",
diff --git a/driver/fuzzed_data_provider.cpp b/driver/fuzzed_data_provider.cpp
index 8b60fd62..ef595d2d 100644
--- a/driver/fuzzed_data_provider.cpp
+++ b/driver/fuzzed_data_provider.cpp
@@ -711,6 +711,29 @@ void Java_com_code_1intelligence_jazzer_runtime_FuzzedDataProviderImpl_reset(
gRemainingBytes = gFuzzerInputSize;
}
+void Java_com_code_1intelligence_jazzer_runtime_FuzzedDataProviderImpl_feed(
+ JNIEnv *env, jclass, jbyteArray input) {
+ // This line is why this function must not be used if FeedFuzzedDataProvider
+ // is also called from native code.
+ delete[] gFuzzerInputStart;
+
+ std::size_t size = env->GetArrayLength(input);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->FatalError("Failed to get length of input");
+ }
+ auto *data = static_cast<uint8_t *>(operator new(size));
+ if (data == nullptr) {
+ env->FatalError("Failed to allocate memory for a copy of the input");
+ }
+ env->GetByteArrayRegion(input, 0, size, reinterpret_cast<jbyte *>(data));
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->FatalError("Failed to copy input");
+ }
+ jazzer::FeedFuzzedDataProvider(data, size);
+}
+
namespace jazzer {
void FeedFuzzedDataProvider(const uint8_t *data, std::size_t size) {
gDataPtr = data;
diff --git a/driver/fuzzed_data_provider_test.cpp b/driver/fuzzed_data_provider_test.cpp
index 05656584..a402d8f1 100644
--- a/driver/fuzzed_data_provider_test.cpp
+++ b/driver/fuzzed_data_provider_test.cpp
@@ -17,11 +17,9 @@
#include <cstddef>
#include <cstdint>
#include <random>
-#include <sstream>
#include <string>
#include <vector>
-#include "fuzz_target_runner.h"
#include "gflags/gflags.h"
#include "gtest/gtest.h"
#include "jvm_tooling.h"
@@ -131,124 +129,6 @@ class FuzzedDataProviderTest : public ::testing::Test {
std::unique_ptr<JVM> FuzzedDataProviderTest::jvm_ = nullptr;
-// see testdata/test/FuzzTargetWithDataProvider.java for the implementation
-// of the fuzz target that asserts that the correct values are received from
-// the data provider.
-const uint8_t kInput[] = {
- // Bytes read from the start
- 0x01, 0x02, // consumeBytes(2): {0x01, 0x02}
-
- 'j', 'a', 'z', 'z', 'e', 'r', // consumeString(6): "jazzer"
- 'j', 'a', 0x00, 'z', 'e', 'r', // consumeString(6): "ja\u0000zer"
- 0xE2, 0x82, 0xAC, 0xC3, 0x9F, // consumeString(2): "€ẞ"
-
- 'j', 'a', 'z', 'z', 'e', 'r', // consumeAsciiString(6): "jazzer"
- 'j', 'a', 0x00, 'z', 'e', 'r', // consumeAsciiString(6): "ja\u0000zer"
- 0xE2, 0x82, 0xAC, 0xC3,
- 0x9F, // consumeAsciiString(5): "\u0062\u0002\u002C\u0043\u001F"
-
- false, false, true, false,
- true, // consumeBooleans(5): { false, false, true, false, true }
- 0xEF, 0xDC, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC,
- 0xFE, // consumeLongs(2): { 0x0123456789ABCDEF, 0xFEDCBA9876543210 }
-
- 0x78, 0x56, 0x34, 0x12, // consumeInts(3): { 0x12345678 }
- 0x56, 0x34, 0x12, // consumeLong():
-
- // Bytes read from the end
- 0x02, 0x03, 0x02, 0x04, // 4x pickValue in array with five elements
-
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 10, // -max for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 9, // max for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 8, // -min for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 7, // min for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 6, // -denorm_min for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 5, // denorm_min for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 4, // NaN for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 3, // -infinity for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 2, // infinity for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 1, // -0.0 for next consumeDouble
- 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
- 0x78, // consumed but unused by consumeDouble()
- 0, // 0.0 for next consumeDouble
-
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 10, // -max for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 9, // max for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 8, // -min for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 7, // min for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 6, // -denorm_min for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 5, // denorm_min for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 4, // NaN for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 3, // -infinity for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 2, // infinity for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 1, // -0.0 for next consumeFloat
- 0x12, 0x34, 0x56, 0x78, 0x90, // consumed but unused by consumeFloat()
- 0, // 0.0 for next consumeFloat
-
- 0x88, 0xAB, 0x61, 0xCB, 0x32, 0xEB, 0x30,
- 0xF9, // consumeDouble(13.37, 31.337): 30.859126145478349 (small range)
- 0x51, 0xF6, 0x1F,
- 0x3A, // consumeFloat(123.0, 777.0): 271.49084 (small range)
- 0x11, 0x4D, 0xFD, 0x54, 0xD6, 0x3D, 0x43, 0x73,
- 0x39, // consumeRegularDouble(): 8.0940194040236032e+307
- 0x16, 0xCF, 0x3D, 0x29, 0x4A, // consumeRegularFloat(): -2.8546307e+38
-
- 0x61, 0xCB, 0x32, 0xEB, 0x30, 0xF9, 0x51,
- 0xF6, // consumeProbabilityDouble(): 0.96218831486039413
- 0x1F, 0x3A, 0x11, 0x4D, // consumeProbabilityFloat(): 0.30104411
- 0xFD, 0x54, 0xD6, 0x3D, 0x43, 0x73, 0x39,
- 0x16, // consumeProbabilityDouble(): 0.086814121166605432
- 0xCF, 0x3D, 0x29, 0x4A, // consumeProbabilityFloat(): 0.28969181
-
- 0x01, // consumeInt(0x12345678, 0x12345679): 0x12345679
- 0x78, // consumeInt(-0x12345678, -0x12345600): -0x12345600
- 0x78, 0x56, 0x34, 0x12, // consumeInt(): 0x12345678
-
- 0x02, // consumeByte(0x12, 0x22): 0x14
- 0x7F, // consumeByte(): 0x7F
-
- 0x01, // consumeBool(): true
-};
-
-TEST_F(FuzzedDataProviderTest, FuzzTargetWithDataProvider) {
- FLAGS_target_class = "test.FuzzTargetWithDataProvider";
- FLAGS_target_args = "";
- FuzzTargetRunner fuzz_target_runner(*jvm_);
-
- ASSERT_EQ(RunResult::kOk, fuzz_target_runner.Run(kInput, sizeof(kInput)));
-}
-
constexpr std::size_t kValidModifiedUtf8NumRuns = 10000;
constexpr std::size_t kValidModifiedUtf8NumBytes = 100000;
constexpr uint32_t kValidModifiedUtf8Seed = 0x12345678;
diff --git a/agent/src/main/native/com/code_intelligence/jazzer/replay/BUILD.bazel b/driver/src/main/native/com/code_intelligence/jazzer/driver/BUILD.bazel
index 6b75fb8b..edb0b4c7 100644
--- a/agent/src/main/native/com/code_intelligence/jazzer/replay/BUILD.bazel
+++ b/driver/src/main/native/com/code_intelligence/jazzer/driver/BUILD.bazel
@@ -1,13 +1,12 @@
load("@fmeum_rules_jni//jni:defs.bzl", "cc_jni_library")
cc_jni_library(
- name = "replay",
- srcs = [
- "com_code_intelligence_jazzer_replay_Replayer.cpp",
+ name = "fuzzed_data_provider_standalone",
+ visibility = [
+ "//agent/src/main/java/com/code_intelligence/jazzer/replay:__pkg__",
+ "//agent/src/test/java/com/code_intelligence/jazzer/runtime:__pkg__",
],
- visibility = ["//agent/src/main/java/com/code_intelligence/jazzer/replay:__pkg__"],
deps = [
- "//agent/src/main/java/com/code_intelligence/jazzer/replay:replay.hdrs",
"//driver:fuzzed_data_provider",
],
)
diff --git a/driver/testdata/test/FuzzTargetWithDataProvider.java b/driver/testdata/test/FuzzTargetWithDataProvider.java
deleted file mode 100644
index 16b230ed..00000000
--- a/driver/testdata/test/FuzzTargetWithDataProvider.java
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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 test;
-
-import com.code_intelligence.jazzer.api.FuzzedDataProvider;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.stream.Collectors;
-
-class FuzzTargetWithDataProvider {
- static {
- System.loadLibrary("jazzer_initialize");
- }
-
- public static <T extends Comparable<T>> void assertEqual(T a, T b) {
- if (a.compareTo(b) != 0) {
- throw new IllegalArgumentException("Expected: " + a + ", got: " + b);
- }
- }
-
- public strictfp static void fuzzerTestOneInput(FuzzedDataProvider data) {
- assertEqual(true, data.consumeBoolean());
-
- assertEqual((byte) 0x7F, data.consumeByte());
- assertEqual((byte) 0x14, data.consumeByte((byte) 0x12, (byte) 0x22));
-
- assertEqual(0x12345678, data.consumeInt());
- assertEqual(-0x12345600, data.consumeInt(-0x12345678, -0x12345600));
- assertEqual(0x12345679, data.consumeInt(0x12345678, 0x12345679));
-
- assertEqual(true, Arrays.equals(new byte[] {0x01, 0x02}, data.consumeBytes(2)));
-
- assertEqual("jazzer", data.consumeString(6));
- assertEqual("ja\u0000zer", data.consumeString(6));
- assertEqual("ۧ", data.consumeString(2));
-
- assertEqual("jazzer", data.consumeAsciiString(6));
- assertEqual("ja\u0000zer", data.consumeAsciiString(6));
- assertEqual("\u0062\u0002\u002C\u0043\u001F", data.consumeAsciiString(5));
-
- assertEqual(true,
- Arrays.equals(new boolean[] {false, false, true, false, true}, data.consumeBooleans(5)));
- assertEqual(true,
- Arrays.equals(new long[] {0x0123456789abdcefL, 0xfedcba9876543210L}, data.consumeLongs(2)));
-
- assertEqual((float) 0.28969181, data.consumeProbabilityFloat());
- assertEqual(0.086814121166605432, data.consumeProbabilityDouble());
- assertEqual((float) 0.30104411, data.consumeProbabilityFloat());
- assertEqual(0.96218831486039413, data.consumeProbabilityDouble());
-
- assertEqual((float) -2.8546307e+38, data.consumeRegularFloat());
- assertEqual(8.0940194040236032e+307, data.consumeRegularDouble());
- assertEqual((float) 271.49084, data.consumeRegularFloat((float) 123.0, (float) 777.0));
- assertEqual(30.859126145478349, data.consumeRegularDouble(13.37, 31.337));
-
- assertEqual((float) 0.0, data.consumeFloat());
- assertEqual((float) -0.0, data.consumeFloat());
- assertEqual(Float.POSITIVE_INFINITY, data.consumeFloat());
- assertEqual(Float.NEGATIVE_INFINITY, data.consumeFloat());
- assertEqual(true, Float.isNaN(data.consumeFloat()));
- assertEqual(Float.MIN_VALUE, data.consumeFloat());
- assertEqual(-Float.MIN_VALUE, data.consumeFloat());
- assertEqual(Float.MIN_NORMAL, data.consumeFloat());
- assertEqual(-Float.MIN_NORMAL, data.consumeFloat());
- assertEqual(Float.MAX_VALUE, data.consumeFloat());
- assertEqual(-Float.MAX_VALUE, data.consumeFloat());
-
- assertEqual(0.0, data.consumeDouble());
- assertEqual(-0.0, data.consumeDouble());
- assertEqual(Double.POSITIVE_INFINITY, data.consumeDouble());
- assertEqual(Double.NEGATIVE_INFINITY, data.consumeDouble());
- assertEqual(true, Double.isNaN(data.consumeDouble()));
- assertEqual(Double.MIN_VALUE, data.consumeDouble());
- assertEqual(-Double.MIN_VALUE, data.consumeDouble());
- assertEqual(Double.MIN_NORMAL, data.consumeDouble());
- assertEqual(-Double.MIN_NORMAL, data.consumeDouble());
- assertEqual(Double.MAX_VALUE, data.consumeDouble());
- assertEqual(-Double.MAX_VALUE, data.consumeDouble());
-
- int[] array = {0, 1, 2, 3, 4};
- assertEqual(4, data.pickValue(array));
- assertEqual(2, (int) data.pickValue(Arrays.stream(array).boxed().toArray()));
- assertEqual(3, data.pickValue(Arrays.stream(array).boxed().collect(Collectors.toList())));
- assertEqual(2, data.pickValue(Arrays.stream(array).boxed().collect(Collectors.toSet())));
-
- // Buffer is almost depleted at this point.
- assertEqual(7, data.remainingBytes());
- assertEqual(true, Arrays.equals(new long[0], data.consumeLongs(3)));
- assertEqual(7, data.remainingBytes());
- assertEqual(true, Arrays.equals(new int[] {0x12345678}, data.consumeInts(3)));
- assertEqual(3, data.remainingBytes());
- assertEqual(0x123456L, data.consumeLong());
-
- // Buffer has been fully consumed at this point
- assertEqual(0, data.remainingBytes());
- assertEqual(0, data.consumeInt());
- assertEqual(0.0, data.consumeDouble());
- assertEqual(-13.37, data.consumeRegularDouble(-13.37, 31.337));
- assertEqual(true, Arrays.equals(new byte[0], data.consumeBytes(4)));
- assertEqual(true, Arrays.equals(new long[0], data.consumeLongs(4)));
- assertEqual("", data.consumeRemainingAsAsciiString());
- assertEqual("", data.consumeRemainingAsString());
- assertEqual("", data.consumeAsciiString(100));
- assertEqual("", data.consumeString(100));
- }
-}