aboutsummaryrefslogtreecommitdiff
path: root/agent/src/main/java
diff options
context:
space:
mode:
authorFabian Meumertzheim <meumertzheim@code-intelligence.com>2021-10-18 13:14:19 +0200
committerFabian Meumertzheim <fabian@meumertzhe.im>2021-10-19 11:07:51 +0200
commitb26fdf6f6c3cd541ff48ce6d5c4c85f6b17b0329 (patch)
tree59c390b41a23f7a55deeef6c2c5b848c662f4f6e /agent/src/main/java
parent9a804bb4272b35b10028a7dc246c6c63176e0eee (diff)
downloadjazzer-api-b26fdf6f6c3cd541ff48ce6d5c4c85f6b17b0329.tar.gz
Allow selecting a particular method for Autofuzz
Diffstat (limited to 'agent/src/main/java')
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel1
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/autofuzz/FuzzTarget.java64
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/utils/Utils.kt27
3 files changed, 86 insertions, 6 deletions
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel b/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel
index 87bbd1ea..ec67a3eb 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel
+++ b/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel
@@ -4,6 +4,7 @@ java_library(
visibility = ["//visibility:public"],
deps = [
"//agent/src/main/java/com/code_intelligence/jazzer/api",
+ "//agent/src/main/java/com/code_intelligence/jazzer/utils",
"@com_github_classgraph_classgraph//:classgraph",
"@com_github_jhalterman_typetools//:typetools",
],
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/FuzzTarget.java b/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/FuzzTarget.java
index 15cab149..9ad44420 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/FuzzTarget.java
+++ b/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/FuzzTarget.java
@@ -15,7 +15,10 @@
package com.code_intelligence.jazzer.autofuzz;
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.code_intelligence.jazzer.utils.Utils;
+import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
+import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
@@ -31,13 +34,33 @@ public class FuzzTarget {
public static void fuzzerInitialize(String[] args) {
if (args.length != 1 || !args[0].contains("::")) {
System.err.println(
- "Expected the argument to --autofuzz to be a method reference (e.g. System.out::println");
+ "Expected the argument to --autofuzz to be a method reference (e.g. System.out::println)");
System.exit(1);
}
methodReference = args[0];
String[] parts = methodReference.split("::", 2);
String className = parts[0];
- String methodName = parts[1];
+ String methodNameAndOptionalDescriptor = parts[1];
+ String methodName;
+ String descriptor;
+ int descriptorStart = methodNameAndOptionalDescriptor.indexOf('(');
+ if (descriptorStart != -1) {
+ methodName = methodNameAndOptionalDescriptor.substring(0, descriptorStart);
+ // URL decode the descriptor to allow copy-pasting from javadoc links such as:
+ // https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html#valueOf(char%5B%5D)
+ try {
+ descriptor =
+ URLDecoder.decode(methodNameAndOptionalDescriptor.substring(descriptorStart), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // UTF-8 is always supported.
+ e.printStackTrace();
+ System.exit(1);
+ return;
+ }
+ } else {
+ methodName = methodNameAndOptionalDescriptor;
+ descriptor = null;
+ }
Class<?> targetClass;
try {
@@ -53,11 +76,35 @@ public class FuzzTarget {
}
targetMethods = Arrays.stream(targetClass.getMethods())
- .filter(method -> method.getName().equals(methodName))
+ .filter(method
+ -> method.getName().equals(methodName)
+ && (descriptor == null
+ || Utils.getReadableDescriptor(method).equals(descriptor)))
.toArray(Method[] ::new);
if (targetMethods.length == 0) {
- System.err.printf("Failed to find accessible methods named %s in class %s for autofuzz",
- methodName, className);
+ if (descriptor == null) {
+ System.err.printf("%nFailed to find accessible methods named %s in class %s for autofuzz.%n"
+ + "Accessible methods:%n%s",
+ methodName, className,
+ Arrays.stream(targetClass.getMethods())
+ .map(method
+ -> String.format(
+ "%s::%s", method.getDeclaringClass().getName(), method.getName()))
+ .distinct()
+ .collect(Collectors.joining(System.lineSeparator())));
+ } else {
+ System.err.printf("%nFailed to find accessible methods named %s in class %s for autofuzz.%n"
+ + "Accessible methods with that name:%n%s",
+ methodName, className,
+ Arrays.stream(targetClass.getMethods())
+ .filter(method -> method.getName().equals(methodName))
+ .map(method
+ -> String.format("%s::%s%s", method.getDeclaringClass().getName(),
+ method.getName(), Utils.getReadableDescriptor(method)))
+ .distinct()
+ .collect(Collectors.joining(System.lineSeparator())));
+ }
+ System.exit(1);
}
throwsDeclarations =
Arrays.stream(targetMethods)
@@ -65,7 +112,12 @@ public class FuzzTarget {
}
public static void fuzzerTestOneInput(FuzzedDataProvider data) throws Throwable {
- Method targetMethod = data.pickValue(targetMethods);
+ Method targetMethod;
+ if (targetMethods.length == 1) {
+ targetMethod = targetMethods[0];
+ } else {
+ targetMethod = data.pickValue(targetMethods);
+ }
try {
Meta.autofuzz(data, targetMethod);
executionsSinceLastInvocation = 0;
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/utils/Utils.kt b/agent/src/main/java/com/code_intelligence/jazzer/utils/Utils.kt
index 6d0b57ec..af8cce9b 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/utils/Utils.kt
+++ b/agent/src/main/java/com/code_intelligence/jazzer/utils/Utils.kt
@@ -39,11 +39,38 @@ val Class<*>.descriptor: String
else -> throw IllegalArgumentException("Unknown class type: $name")
}
+val Class<*>.readableDescriptor: String
+ get() = when {
+ isPrimitive -> {
+ when (this) {
+ Boolean::class.javaPrimitiveType -> "boolean"
+ Byte::class.javaPrimitiveType -> "byte"
+ Char::class.javaPrimitiveType -> "char"
+ Short::class.javaPrimitiveType -> "short"
+ Int::class.javaPrimitiveType -> "int"
+ Long::class.javaPrimitiveType -> "long"
+ Float::class.javaPrimitiveType -> "float"
+ Double::class.javaPrimitiveType -> "double"
+ java.lang.Void::class.javaPrimitiveType -> "void"
+ else -> throw IllegalStateException("Unknown primitive type: $name")
+ }
+ }
+ isArray -> "${componentType.readableDescriptor}[]"
+ java.lang.Object::class.java.isAssignableFrom(this) -> name
+ else -> throw IllegalArgumentException("Unknown class type: $name")
+ }
+
val Executable.descriptor: String
get() = parameterTypes.joinToString(separator = "", prefix = "(", postfix = ")") { parameterType ->
parameterType.descriptor
} + if (this is Method) returnType.descriptor else "V"
+// This does not include the return type as the parameter descriptors already uniquely identify the executable.
+val Executable.readableDescriptor: String
+ get() = parameterTypes.joinToString(separator = ",", prefix = "(", postfix = ")") { parameterType ->
+ parameterType.readableDescriptor
+ }
+
fun simpleFastHash(vararg strings: String): Int {
var hash = 0
for (string in strings) {