aboutsummaryrefslogtreecommitdiff
path: root/agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java')
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/runtime/FuzzedDataProviderImpl.java187
1 files changed, 177 insertions, 10 deletions
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 fe4d8ac7..b7aad33e 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
@@ -15,9 +15,119 @@
package com.code_intelligence.jazzer.runtime;
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
-
-public class FuzzedDataProviderImpl implements FuzzedDataProvider {
- public FuzzedDataProviderImpl() {}
+import com.github.fmeum.rules_jni.RulesJni;
+import sun.misc.Unsafe;
+
+public class FuzzedDataProviderImpl implements FuzzedDataProvider, AutoCloseable {
+ static {
+ // The replayer loads a standalone version of the FuzzedDataProvider.
+ if (System.getProperty("jazzer.is_replayer") == null) {
+ RulesJni.loadLibrary("jazzer_driver", "/com/code_intelligence/jazzer/driver");
+ }
+ nativeInit();
+ }
+
+ private static native void nativeInit();
+
+ private final boolean ownsNativeData;
+ private long originalDataPtr;
+ private int originalRemainingBytes;
+
+ // Accessed in fuzzed_data_provider.cpp.
+ private long dataPtr;
+ private int remainingBytes;
+
+ private FuzzedDataProviderImpl(long dataPtr, int remainingBytes, boolean ownsNativeData) {
+ this.ownsNativeData = ownsNativeData;
+ this.originalDataPtr = dataPtr;
+ this.dataPtr = dataPtr;
+ this.originalRemainingBytes = remainingBytes;
+ this.remainingBytes = remainingBytes;
+ }
+
+ /**
+ * Creates a {@link FuzzedDataProvider} that consumes bytes from an already existing native array.
+ *
+ * <ul>
+ * <li>{@link #close()} <b>must</b> be called on instances created with this method to free the
+ * native copy of the Java
+ * {@code byte} array.
+ * <li>{@link #setNativeData(long, int)} <b>must not</b> be called on instances created with this
+ * method.
+ *
+ * @param data the raw bytes used as input
+ * @return a {@link FuzzedDataProvider} backed by {@code data}
+ */
+ public static FuzzedDataProviderImpl withJavaData(byte[] data) {
+ return new FuzzedDataProviderImpl(allocateNativeCopy(data), data.length, true);
+ }
+
+ /**
+ * Creates a {@link FuzzedDataProvider} that consumes bytes from an already existing native array.
+ *
+ * <p>The backing array can be set at any time using {@link #setNativeData(long, int)} and is
+ * initially empty.
+ *
+ * @return a {@link FuzzedDataProvider} backed by an empty array.
+ */
+ public static FuzzedDataProviderImpl withNativeData() {
+ return new FuzzedDataProviderImpl(0, 0, false);
+ }
+
+ /**
+ * Replaces the current native backing array.
+ *
+ * <p><b>Must not</b> be called on instances created with {@link #withJavaData(byte[])}.
+ *
+ * @param dataPtr a native pointer to the new backing array
+ * @param dataLength the length of the new backing array
+ */
+ public void setNativeData(long dataPtr, int dataLength) {
+ this.originalDataPtr = dataPtr;
+ this.dataPtr = dataPtr;
+ this.originalRemainingBytes = dataLength;
+ this.remainingBytes = dataLength;
+ }
+
+ /**
+ * Resets the FuzzedDataProvider state to read from the beginning to the end of its current
+ * backing item.
+ */
+ public void reset() {
+ dataPtr = originalDataPtr;
+ remainingBytes = originalRemainingBytes;
+ }
+
+ /**
+ * Releases native memory allocated for this instance (if any).
+ *
+ * <p>While the instance should not be used after this method returns, no usage of {@link
+ * FuzzedDataProvider} methods can result in memory corruption.
+ */
+ @Override
+ public void close() {
+ if (originalDataPtr == 0) {
+ return;
+ }
+ if (ownsNativeData) {
+ UNSAFE.freeMemory(originalDataPtr);
+ }
+ // Prevent double-frees and use-after-frees by effectively making all methods no-ops after
+ // close() has been called.
+ originalDataPtr = 0;
+ originalRemainingBytes = 0;
+ dataPtr = 0;
+ remainingBytes = 0;
+ }
+
+ private static final Unsafe UNSAFE = UnsafeProvider.getUnsafe();
+ private static final long BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
+
+ private static long allocateNativeCopy(byte[] data) {
+ long nativeCopy = UNSAFE.allocateMemory(data.length);
+ UNSAFE.copyMemory(data, BYTE_ARRAY_OFFSET, null, nativeCopy, data.length);
+ return nativeCopy;
+ }
@Override public native boolean consumeBoolean();
@@ -25,23 +135,51 @@ public class FuzzedDataProviderImpl implements FuzzedDataProvider {
@Override public native byte consumeByte();
- @Override public native byte consumeByte(byte min, byte max);
+ @Override
+ public byte consumeByte(byte min, byte max) {
+ if (min > max) {
+ throw new IllegalArgumentException(
+ String.format("min must be <= max (got min: %d, max: %d)", min, max));
+ }
+ return consumeByteUnchecked(min, max);
+ }
@Override public native short consumeShort();
- @Override public native short consumeShort(short min, short max);
+ @Override
+ public short consumeShort(short min, short max) {
+ if (min > max) {
+ throw new IllegalArgumentException(
+ String.format("min must be <= max (got min: %d, max: %d)", min, max));
+ }
+ return consumeShortUnchecked(min, max);
+ }
@Override public native short[] consumeShorts(int maxLength);
@Override public native int consumeInt();
- @Override public native int consumeInt(int min, int max);
+ @Override
+ public int consumeInt(int min, int max) {
+ if (min > max) {
+ throw new IllegalArgumentException(
+ String.format("min must be <= max (got min: %d, max: %d)", min, max));
+ }
+ return consumeIntUnchecked(min, max);
+ }
@Override public native int[] consumeInts(int maxLength);
@Override public native long consumeLong();
- @Override public native long consumeLong(long min, long max);
+ @Override
+ public long consumeLong(long min, long max) {
+ if (min > max) {
+ throw new IllegalArgumentException(
+ String.format("min must be <= max (got min: %d, max: %d)", min, max));
+ }
+ return consumeLongUnchecked(min, max);
+ }
@Override public native long[] consumeLongs(int maxLength);
@@ -49,13 +187,27 @@ public class FuzzedDataProviderImpl implements FuzzedDataProvider {
@Override public native float consumeRegularFloat();
- @Override public native float consumeRegularFloat(float min, float max);
+ @Override
+ public float consumeRegularFloat(float min, float max) {
+ if (min > max) {
+ throw new IllegalArgumentException(
+ String.format("min must be <= max (got min: %f, max: %f)", min, max));
+ }
+ return consumeRegularFloatUnchecked(min, max);
+ }
@Override public native float consumeProbabilityFloat();
@Override public native double consumeDouble();
- @Override public native double consumeRegularDouble(double min, double max);
+ @Override
+ public double consumeRegularDouble(double min, double max) {
+ if (min > max) {
+ throw new IllegalArgumentException(
+ String.format("min must be <= max (got min: %f, max: %f)", min, max));
+ }
+ return consumeRegularDoubleUnchecked(min, max);
+ }
@Override public native double consumeRegularDouble();
@@ -63,7 +215,14 @@ public class FuzzedDataProviderImpl implements FuzzedDataProvider {
@Override public native char consumeChar();
- @Override public native char consumeChar(char min, char max);
+ @Override
+ public char consumeChar(char min, char max) {
+ if (min > max) {
+ throw new IllegalArgumentException(
+ String.format("min must be <= max (got min: %c, max: %c)", min, max));
+ }
+ return consumeCharUnchecked(min, max);
+ }
@Override public native char consumeCharNoSurrogates();
@@ -80,4 +239,12 @@ public class FuzzedDataProviderImpl implements FuzzedDataProvider {
@Override public native byte[] consumeRemainingAsBytes();
@Override public native int remainingBytes();
+
+ private native byte consumeByteUnchecked(byte min, byte max);
+ private native short consumeShortUnchecked(short min, short max);
+ private native char consumeCharUnchecked(char min, char max);
+ private native int consumeIntUnchecked(int min, int max);
+ private native long consumeLongUnchecked(long min, long max);
+ private native float consumeRegularFloatUnchecked(float min, float max);
+ private native double consumeRegularDoubleUnchecked(double min, double max);
}