aboutsummaryrefslogtreecommitdiff
path: root/agent
diff options
context:
space:
mode:
authorKhaled Yakdan <yakdan@code-intelligence.com>2021-10-17 21:49:09 +0200
committerFabian Meumertzheim <fabian@meumertzhe.im>2021-10-19 11:07:51 +0200
commit9a804bb4272b35b10028a7dc246c6c63176e0eee (patch)
tree9f8f1cbc7999aae3db744ffb6db484ebcd2956fc /agent
parent65b3309b8b027a945b52155772e7690fb7581533 (diff)
downloadjazzer-api-9a804bb4272b35b10028a7dc246c6c63176e0eee.tar.gz
Handle creating classes with a default constructor and setter methods
Diffstat (limited to 'agent')
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java4
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/autofuzz/Meta.java46
-rw-r--r--agent/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel15
-rw-r--r--agent/src/test/java/com/code_intelligence/jazzer/autofuzz/SettersTest.java43
-rw-r--r--agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/BUILD.bazel5
-rw-r--r--agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/EmployeeWithSetters.java56
6 files changed, 159 insertions, 10 deletions
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java b/agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java
index 30ae526a..b1f38b50 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java
+++ b/agent/src/main/java/com/code_intelligence/jazzer/api/FuzzedDataProvider.java
@@ -283,7 +283,7 @@ public interface FuzzedDataProvider {
* <p><b>Note:</b> The distribution of picks is not perfectly uniform.
*
* @param collection the {@link Collection} to pick an element from.
- * @param <T> the type of a collection element
+ * @param <T> the type of the collection element
* @return an element from {@code collection} chosen based on the fuzzer input
*/
@SuppressWarnings("unchecked")
@@ -304,7 +304,7 @@ public interface FuzzedDataProvider {
* <p><b>Note:</b> The distribution of picks is not perfectly uniform.
*
* @param array the array to pick an element from.
- * @param <T> the type of an array element
+ * @param <T> the type of the array element
* @return an element from {@code array} chosen based on the fuzzer input
*/
default<T> T pickValue(T[] array) {
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 0d0c3190..fda9748b 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
@@ -18,6 +18,7 @@ import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfoList;
import io.github.classgraph.ScanResult;
+import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
@@ -25,10 +26,7 @@ import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.WeakHashMap;
+import java.util.*;
import java.util.stream.Collectors;
import net.jodah.typetools.TypeResolver;
import net.jodah.typetools.TypeResolver.Unknown;
@@ -142,7 +140,19 @@ public class Meta {
}
return consume(data, data.pickValue(implementingClasses));
} else if (type.getConstructors().length > 0) {
- return autofuzz(data, data.pickValue(type.getConstructors()));
+ Constructor<?> constructor = data.pickValue(type.getConstructors());
+ Object obj = autofuzz(data, constructor);
+ if (constructor.getParameterCount() == 0) {
+ List<Method> potentialSetters = getPotentialSetters(type);
+ if (!potentialSetters.isEmpty()) {
+ List<Method> pickedSetters =
+ data.pickValues(potentialSetters, data.consumeInt(0, potentialSetters.size()));
+ for (Method setter : pickedSetters) {
+ autofuzz(data, setter, obj);
+ }
+ }
+ }
+ return obj;
} else if (getNestedBuilderClasses(type).size() > 0) {
List<Class<?>> nestedBuilderClasses = getNestedBuilderClasses(type);
Class<?> pickedBuilder = data.pickValue(nestedBuilderClasses);
@@ -160,16 +170,23 @@ public class Meta {
Method builderMethod = data.pickValue(originalObjectCreationMethods);
- Object obj = autofuzz(data, data.pickValue(pickedBuilder.getConstructors()));
+ Object builderObj = autofuzz(data, data.pickValue(pickedBuilder.getConstructors()));
for (Method method : pickedMethods) {
- obj = autofuzz(data, method, obj);
+ builderObj = autofuzz(data, method, builderObj);
}
try {
- return builderMethod.invoke(obj);
+ return builderMethod.invoke(builderObj);
} catch (Exception e) {
throw new AutofuzzConstructionException(e);
}
+ } else {
+ Constructor<?>[] c = type.getDeclaredConstructors();
+ System.err.printf("ctor: %s\n", c[0].toGenericString());
+ System.err.printf(" public %b\n", Modifier.isPublic(c[0].getModifiers()));
+ System.err.printf(" private %b\n", Modifier.isPrivate(c[0].getModifiers()));
+ System.err.printf(" protected %b\n", Modifier.isProtected(c[0].getModifiers()));
+ // System.err.printf(" protected %b\n", Modifier.i(c[0].getModifiers()));
}
return null;
}
@@ -180,6 +197,19 @@ public class Meta {
.collect(Collectors.toList());
}
+ private static List<Method> getPotentialSetters(Class<?> type) {
+ List<Method> potentialSetters = new ArrayList<>();
+ List<Method> methods = Arrays.asList(type.getMethods());
+ methods.sort(Comparator.comparing(Method::getName));
+ for (Method method : methods) {
+ if (void.class.equals(method.getReturnType()) && method.getParameterCount() == 1
+ && method.getName().startsWith("set")) {
+ potentialSetters.add(method);
+ }
+ }
+ return potentialSetters;
+ }
+
private static Object[] consumeArguments(FuzzedDataProvider data, Executable executable) {
Object[] result;
try {
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 84d86e2a..cc71e09d 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
@@ -42,3 +42,18 @@ java_test(
"@maven//:junit_junit",
],
)
+
+java_test(
+ name = "SettersTest",
+ size = "small",
+ srcs = [
+ "SettersTest.java",
+ ],
+ test_class = "com.code_intelligence.jazzer.autofuzz.SettersTest",
+ deps = [
+ "//agent/src/main/java/com/code_intelligence/jazzer/api",
+ "//agent/src/main/java/com/code_intelligence/jazzer/autofuzz",
+ "//agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata:test_data",
+ "@maven//:junit_junit",
+ ],
+)
diff --git a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/SettersTest.java b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/SettersTest.java
new file mode 100644
index 00000000..59a46636
--- /dev/null
+++ b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/SettersTest.java
@@ -0,0 +1,43 @@
+// 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 com.code_intelligence.jazzer.autofuzz.testdata.EmployeeWithSetters;
+import java.util.Arrays;
+import org.junit.Test;
+
+public class SettersTest {
+ FuzzedDataProvider data =
+ CannedFuzzedDataProvider.create(Arrays.asList(0, // pick first constructor
+ 2, // pick two setters
+ 1, // pick second setter
+ 0, // pick first setter
+ 6, // remaining bytes
+ "foo", // setFirstName
+ 26 // setAge
+ ));
+
+ @Test
+ public void testEmptyConstructorWithSetters() {
+ EmployeeWithSetters employee = new EmployeeWithSetters();
+ employee.setFirstName("foo");
+ employee.setAge(26);
+ assertEquals(Meta.consume(data, EmployeeWithSetters.class), employee);
+ }
+}
diff --git a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/BUILD.bazel b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/BUILD.bazel
new file mode 100644
index 00000000..c2c68803
--- /dev/null
+++ b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/BUILD.bazel
@@ -0,0 +1,5 @@
+java_library(
+ name = "test_data",
+ srcs = glob(["*.java"]),
+ visibility = ["//visibility:public"],
+)
diff --git a/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/EmployeeWithSetters.java b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/EmployeeWithSetters.java
new file mode 100644
index 00000000..2c76a61f
--- /dev/null
+++ b/agent/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/EmployeeWithSetters.java
@@ -0,0 +1,56 @@
+// 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.testdata;
+
+import java.util.Objects;
+
+public class EmployeeWithSetters {
+ private String firstName;
+ private String lastName;
+ private String jobTitle;
+ private int age;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ EmployeeWithSetters hero = (EmployeeWithSetters) o;
+ return age == hero.age && Objects.equals(firstName, hero.firstName)
+ && Objects.equals(lastName, hero.lastName) && Objects.equals(jobTitle, hero.jobTitle);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(firstName, lastName, jobTitle, age);
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public void setJobTitle(String jobTitle) {
+ this.jobTitle = jobTitle;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+}