diff options
author | Fabian Meumertzheim <meumertzheim@code-intelligence.com> | 2021-10-18 13:14:19 +0200 |
---|---|---|
committer | Fabian Meumertzheim <fabian@meumertzhe.im> | 2021-10-19 11:07:51 +0200 |
commit | b26fdf6f6c3cd541ff48ce6d5c4c85f6b17b0329 (patch) | |
tree | 59c390b41a23f7a55deeef6c2c5b848c662f4f6e /agent | |
parent | 9a804bb4272b35b10028a7dc246c6c63176e0eee (diff) | |
download | jazzer-api-b26fdf6f6c3cd541ff48ce6d5c4c85f6b17b0329.tar.gz |
Allow selecting a particular method for Autofuzz
Diffstat (limited to 'agent')
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) { |