diff options
author | Fabian Meumertzheim <fabian@meumertzhe.im> | 2022-08-04 09:57:03 +0200 |
---|---|---|
committer | Fabian Meumertzheim <fabian@meumertzhe.im> | 2022-08-10 12:50:59 +0200 |
commit | 5585339ca6a009d2e2507513b35f05682358f4ba (patch) | |
tree | 4a4fefbe35db542e602413d9ac5d59d32553cc50 | |
parent | 678ceb53e8c2f045b550f3ddbd80ed7a9818de41 (diff) | |
download | jazzer-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.bazel | 3 | ||||
-rw-r--r-- | agent/src/main/java/com/code_intelligence/jazzer/replay/Replayer.java | 7 | ||||
-rw-r--r-- | agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java | 5 | ||||
-rw-r--r-- | agent/src/main/native/com/code_intelligence/jazzer/replay/com_code_intelligence_jazzer_replay_Replayer.cpp | 46 | ||||
-rw-r--r-- | agent/src/test/java/com/code_intelligence/jazzer/runtime/BUILD.bazel | 12 | ||||
-rw-r--r-- | agent/src/test/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImplTest.java | 235 | ||||
-rw-r--r-- | driver/BUILD.bazel | 11 | ||||
-rw-r--r-- | driver/fuzzed_data_provider.cpp | 23 | ||||
-rw-r--r-- | driver/fuzzed_data_provider_test.cpp | 120 | ||||
-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.java | 118 |
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)); - } -} |