From bc8cb4614b97cc1d905e5d1e083ea084ddfaa9af Mon Sep 17 00:00:00 2001 From: Khaled Yakdan Date: Thu, 14 Oct 2021 15:25:34 +0200 Subject: Create Objects from classes implementing an interface --- .../code_intelligence/jazzer/autofuzz/Meta.java | 22 ++++- .../code_intelligence/jazzer/autofuzz/BUILD.bazel | 14 +++ .../jazzer/autofuzz/InterfaceCreationTest.java | 106 +++++++++++++++++++++ .../jazzer/autofuzz/MetaTest.java | 2 - driver/fuzz_target_runner.cpp | 2 +- 5 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 agent/src/test/java/com/code_intelligence/jazzer/autofuzz/InterfaceCreationTest.java diff --git a/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java b/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java index 1f8a21c6..8a640637 100644 --- a/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java +++ b/agent/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java @@ -15,6 +15,9 @@ package com.code_intelligence.jazzer.autofuzz; import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfoList; +import io.github.classgraph.ScanResult; import java.io.ByteArrayInputStream; import java.lang.reflect.Array; import java.lang.reflect.Constructor; @@ -23,10 +26,14 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; +import java.util.List; +import java.util.WeakHashMap; import net.jodah.typetools.TypeResolver; import net.jodah.typetools.TypeResolver.Unknown; public class Meta { + static WeakHashMap, List>> cache = new WeakHashMap<>(); + public static Object consume(FuzzedDataProvider data, Class type) { if (type == byte.class || type == Byte.class) { return data.consumeByte(); @@ -68,8 +75,19 @@ public class Meta { return new ByteArrayInputStream(data.consumeBytes(data.remainingBytes() / 2)); } else if (type.isEnum()) { return data.pickValue(type.getEnumConstants()); - } else if (Modifier.isAbstract(type.getModifiers())) { - } else if (type.isInterface()) { + } else if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) { + List> implementingClasses = cache.get(type); + if (implementingClasses == null) { + try (ScanResult result = + new ClassGraph().enableClassInfo().enableInterClassDependencies().scan()) { + ClassInfoList children = + type.isInterface() ? result.getClassesImplementing(type) : result.getSubclasses(type); + implementingClasses = + children.getStandardClasses().filter(cls -> !cls.isAbstract()).loadClasses(); + cache.put(type, implementingClasses); + } + } + return consume(data, data.pickValue(implementingClasses)); } else if (type.getConstructors().length > 0) { return autofuzz(data, data.pickValue(type.getConstructors())); } diff --git a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel index c25d7147..454e8e3f 100644 --- a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel +++ b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel @@ -14,3 +14,17 @@ java_test( "@maven//:junit_junit", ], ) + +java_test( + name = "InterfaceCreationTest", + size = "small", + srcs = [ + "InterfaceCreationTest.java", + ], + test_class = "com.code_intelligence.jazzer.autofuzz.InterfaceCreationTest", + deps = [ + "//agent/src/main/java/com/code_intelligence/jazzer/api", + "//agent/src/main/java/com/code_intelligence/jazzer/autofuzz", + "@maven//:junit_junit", + ], +) diff --git a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/InterfaceCreationTest.java b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/InterfaceCreationTest.java new file mode 100644 index 00000000..d15cfd89 --- /dev/null +++ b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/InterfaceCreationTest.java @@ -0,0 +1,106 @@ +// 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.autofuzz; + +import static org.junit.Assert.assertEquals; + +import com.code_intelligence.jazzer.api.CannedFuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import java.util.Arrays; +import java.util.Objects; +import org.junit.Test; + +interface InterfaceA { + void foo(); + + void bar(); +} + +abstract class ClassA1 implements InterfaceA { + @Override + public void foo() {} +} + +class ClassB1 extends ClassA1 { + int n; + + public ClassB1(int _n) { + n = _n; + } + + @Override + public void bar() {} + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ClassB1 classB1 = (ClassB1) o; + return n == classB1.n; + } + + @Override + public int hashCode() { + return Objects.hash(n); + } +} + +class ClassB2 implements InterfaceA { + String s; + + public ClassB2(String _s) { + s = _s; + } + + @Override + public void foo() {} + + @Override + public void bar() {} + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ClassB2 classB2 = (ClassB2) o; + return Objects.equals(s, classB2.s); + } + + @Override + public int hashCode() { + return Objects.hash(s); + } +} + +public class InterfaceCreationTest { + FuzzedDataProvider data = CannedFuzzedDataProvider.create(Arrays.asList(0, // pick ClassB1 + 0, // pick first constructor + 5, // arg for ClassB1 constructor + 1, // pick ClassB2 + 0, // pick first constructor + 8, // remaining bytes + "test" // arg for ClassB2 constructor + )); + + @Test + public void testConsumeInterface() { + assertEquals(Meta.consume(data, InterfaceA.class), new ClassB1(5)); + assertEquals(Meta.consume(data, InterfaceA.class), new ClassB2("test")); + } +} diff --git a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java index c491ed66..52ec1eb0 100644 --- a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java +++ b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java @@ -20,10 +20,8 @@ import static org.junit.Assert.assertTrue; import com.code_intelligence.jazzer.api.CannedFuzzedDataProvider; import com.code_intelligence.jazzer.api.FuzzedDataProvider; import com.google.json.JsonSanitizer; - import java.util.Arrays; import java.util.Collections; - import org.junit.Test; public class MetaTest { diff --git a/driver/fuzz_target_runner.cpp b/driver/fuzz_target_runner.cpp index 0bdaedf5..b71a937a 100644 --- a/driver/fuzz_target_runner.cpp +++ b/driver/fuzz_target_runner.cpp @@ -155,7 +155,7 @@ FuzzTargetRunner::FuzzTargetRunner( jclass string_class = jvm.FindClass("java/lang/String"); jobjectArray arg_array = jvm.GetEnv().NewObjectArray( fuzz_target_args_tokens.size(), string_class, nullptr); - for (std::size_t i = 0; i < fuzz_target_args_tokens.size(); i++) { + for (jint i = 0; i < fuzz_target_args_tokens.size(); i++) { jstring str = env.NewStringUTF(fuzz_target_args_tokens[i].c_str()); env.SetObjectArrayElement(arg_array, i, str); } -- cgit v1.2.3