Skip to content

Commit

Permalink
add callgraph benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
waderwu committed Mar 26, 2022
1 parent 583dfe6 commit 4f303c8
Show file tree
Hide file tree
Showing 31 changed files with 5,001 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

# idea
*.iml
.idea
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# Benchmark
benchmark of java static analysis

## CallGraph Benchmark
source is from https://bitbucket.org/delors/cats/src/master/

260 changes: 260 additions & 0 deletions docs/callgraph/Classloading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
# Classloading

Tests related to the usage of `java.lang.ClassLoader`s. The following test cases are available and
listed in the `infrastructure incompatible testcases`

## CL1
This test case uses an `URLClassLoader` in order to load classes from an external *.jar* file.
That class will be instantiated using `Class<?>.newInstance`.
Afterwards, it calls the `compare` on the `Comparator` interface, which will resolve to the `IntComparator`
from the given *.jar* at runtime.

```java
package demo;

import lib.annotations.callgraph.IndirectCall;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Comparator;

public class Demo {

private static final String DIR = System.getProperty("user.dir") + "/resources/";
private static URL CLv1;

static {
try {
CLv1 = new URL("file://" + DIR + "classloading-version-1.jar");
} catch (MalformedURLException e) {
e.printStackTrace();
}
}

private static final String CLS_NAME = "lib.IntComparator";

@IndirectCall(name = "compareTo", returnType = int.class, line = 34, resolvedTargets = "Ljava/lang/Integer;")
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ClassLoader parent = ClassLoader.getSystemClassLoader();
URL[] urls = new URL[] { CLv1 };
URLClassLoader cl = URLClassLoader.newInstance(urls, parent);
Class<?> cls = cl.loadClass(CLS_NAME);
Comparator<Integer> comparator = (Comparator<Integer>) cls.newInstance();
Integer one = Integer.valueOf(1);
comparator.compare(one, one);
}
}

```

## CL2
This test case is basically the same as CL1. In contrast to this the generic type of the class is
already specified before calling `Class<Comparator<Integer>>.newInstance`.

```java
package demo;

import lib.annotations.callgraph.IndirectCall;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Comparator;

public class Main {

private static final String DIR = System.getProperty("user.dir") + "/resources/";
private static URL CLv2;

static {
try {
CLv2 = new URL("file://" + DIR + "classloading-version-2.jar");
} catch (MalformedURLException e) {
e.printStackTrace();
}
}

private static final String CLS_NAME = "lib.IntComparator";

@IndirectCall(name = "compareTo", returnType = int.class, line = 35, resolvedTargets = "Ljava/lang/Integer;")
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ClassLoader parent = ClassLoader.getSystemClassLoader();
URL[] urls = new URL[] { CLv2 };
URLClassLoader cl = URLClassLoader.newInstance(urls, parent);
Class<Comparator<Integer>> cls = (Class<Comparator<Integer>>) cl.loadClass(CLS_NAME);
Comparator<Integer> comparator = cls.newInstance();
Integer one = Integer.valueOf(1);
comparator.compare(one, one);
}
}
```


## CL3
In this test case, to different versions of a class are loaded using an `URLClassLoader`.
On both versions a call to `<Comparator<Integer>>.compare` is performed.
After those different versioned classes are loaded, methods are called on the classes which must
be resolved to different targets.

```java
package cl;

import lib.annotations.callgraph.IndirectCall;
import lib.annotations.callgraph.IndirectCalls;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Comparator;

public class Demo {

//private static final String DIR = System.getProperty("user.dir") + "/resources/";
private static final String DIR = "/Users/mreif/Programming/git/jcg/infrastructure_incompatible_testcases/CL3/src/resources/";
private static URL CLv1;
private static URL CLv2;
private static final String CLS_NAME = "lib.IntComparator";

static {
try {
CLv1 = new URL("file://" + DIR + "classloading-version-1.jar");
CLv2 = new URL("file://" + DIR + "classloading-version-2.jar");
} catch (MalformedURLException e) {
e.printStackTrace();
}
}

@IndirectCalls({
@IndirectCall(name = "compare", line = 53, returnType = int.class, resolvedTargets = "Ljava/lang/Integer;"),
@IndirectCall(name = "gc", line = 54, resolvedTargets = "Ljava/lang/System;")
})
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ClassLoader oldParent = Thread.currentThread().getContextClassLoader();
ClassLoader newParent = Demo.class.getClassLoader();

URL[] oldResource = new URL[]{CLv1};
URL[] newResource = new URL[]{CLv2};

URLClassLoader oldVersionLoader = new URLClassLoader(oldResource, oldParent);
URLClassLoader newVersionLoader= new URLClassLoader(newResource, newParent);

System.out.println(CLv1.toExternalForm());

Class<?> oldClass = oldVersionLoader.loadClass(CLS_NAME);
Class<?> newClass = newVersionLoader.loadClass(CLS_NAME);

Comparator<Integer> oldComparator = (Comparator<Integer>) oldClass.newInstance();
Comparator<Integer> newComparator = (Comparator<Integer>) newClass.newInstance();

Integer one = new Integer(1);

oldComparator.compare(one,one);
newComparator.compare(one,one);
}
}
```

## CL4
[//]: # (MAIN: cl4.Demo)
This test case defines a custom classloader, that loads the class `lib.IntComparator` from a byte array.
The array *bytes* contains the bytes of the following class:
```java
package lib;

import java.util.Comparator;
import cl4.Demo;

public class IntComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
Demo.callback;
return o1.compareTo(o2);
}
}

```
In order to extract the bytes, we used `java.nio.file.Files.readAllBytes()`.

```java
// cl4/Demo.java
package cl4;

import lib.annotations.callgraph.IndirectCall;
import java.util.Comparator;

public class Demo {

@IndirectCall(name = "callback", line = 14, resolvedTargets = "Lcl4/Demo;")
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ClassLoader cl = new ByteClassLoader(ClassLoader.getSystemClassLoader());
Class<?> cls = cl.loadClass("lib.IntComparator");
Comparator<Integer> comparator = (Comparator<Integer>) cls.newInstance();
Integer one = 1;
comparator.compare(one, one);
}

public static void callback() { }
}
```
```java
// cl4/ByteClassLoader.java
package cl4;

import java.security.SecureClassLoader;

public class ByteClassLoader extends SecureClassLoader {

public ByteClassLoader(ClassLoader parent) {
super(parent);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name.equals("lib.IntComparator")) {
return defineClass(name, bytes, 0, bytes.length);
}
return super.findClass(name);
}

private final byte[] bytes = new byte[]{
-54, -2, -70, -66, 0, 0, 0, 52, 0, 39, 10, 0, 7, 0, 26, 10, 0, 27, 0, 28, 10, 0, 4, 0,
29, 7, 0, 30, 10, 0, 6, 0, 31, 7, 0, 32, 7, 0, 33, 7, 0, 34, 1, 0, 6, 60, 105, 110,
105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78,
117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98,
108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 19, 76, 108, 105, 98, 47, 73, 110,
116, 67, 111, 109, 112, 97, 114, 97, 116, 111, 114, 59, 1, 0, 7, 99, 111, 109, 112, 97, 114, 101, 1, 0,
41, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101, 103, 101, 114, 59, 76, 106, 97,
118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101, 103, 101, 114, 59, 41, 73, 1, 0, 2, 111, 49, 1,
0, 19, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101, 103, 101, 114, 59, 1, 0, 2,
111, 50, 1, 0, 39, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59,
76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 41, 73, 1, 0, 9, 83,
105, 103, 110, 97, 116, 117, 114, 101, 1, 0, 61, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98,
106, 101, 99, 116, 59, 76, 106, 97, 118, 97, 47, 117, 116, 105, 108, 47, 67, 111, 109, 112, 97, 114, 97, 116,
111, 114, 60, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101, 103, 101, 114, 59, 62, 59,
1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 18, 73, 110, 116, 67, 111, 109, 112, 97,
114, 97, 116, 111, 114, 46, 106, 97, 118, 97, 12, 0, 9, 0, 10, 7, 0, 35, 12, 0, 36, 0, 10, 12,
0, 37, 0, 38, 1, 0, 17, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101, 103, 101, 114,
12, 0, 16, 0, 17, 1, 0, 17, 108, 105, 98, 47, 73, 110, 116, 67, 111, 109, 112, 97, 114, 97, 116, 111,
114, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 20, 106,
97, 118, 97, 47, 117, 116, 105, 108, 47, 67, 111, 109, 112, 97, 114, 97, 116, 111, 114, 1, 0, 8, 99, 108,
52, 47, 68, 101, 109, 111, 1, 0, 8, 99, 97, 108, 108, 98, 97, 99, 107, 1, 0, 9, 99, 111, 109, 112,
97, 114, 101, 84, 111, 1, 0, 22, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101,
103, 101, 114, 59, 41, 73, 0, 33, 0, 6, 0, 7, 0, 1, 0, 8, 0, 0, 0, 3, 0, 1, 0, 9,
0, 10, 0, 1, 0, 11, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0,
0, 0, 2, 0, 12, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 0, 13, 0, 0, 0, 12, 0, 1, 0,
0, 0, 5, 0, 14, 0, 15, 0, 0, 0, 1, 0, 16, 0, 17, 0, 1, 0, 11, 0, 0, 0, 75, 0,
2, 0, 3, 0, 0, 0, 9, -72, 0, 2, 43, 44, -74, 0, 3, -84, 0, 0, 0, 2, 0, 12, 0, 0,
0, 10, 0, 2, 0, 0, 0, 10, 0, 3, 0, 11, 0, 13, 0, 0, 0, 32, 0, 3, 0, 0, 0, 9,
0, 14, 0, 15, 0, 0, 0, 0, 0, 9, 0, 18, 0, 19, 0, 1, 0, 0, 0, 9, 0, 20, 0, 19,
0, 2, 16, 65, 0, 16, 0, 21, 0, 1, 0, 11, 0, 0, 0, 55, 0, 3, 0, 3, 0, 0, 0, 13,
42, 43, -64, 0, 4, 44, -64, 0, 4, -74, 0, 5, -84, 0, 0, 0, 2, 0, 12, 0, 0, 0, 6, 0,
1, 0, 0, 0, 7, 0, 13, 0, 0, 0, 12, 0, 1, 0, 0, 0, 13, 0, 14, 0, 15, 0, 0, 0,
2, 0, 22, 0, 0, 0, 2, 0, 23, 0, 24, 0, 0, 0, 2, 0, 25
};
}
```
[//]: # (END)
74 changes: 74 additions & 0 deletions docs/callgraph/DynamicProxies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Dynamic Proxies
Using `java.lang.reflect.InvocationHandler` type-safe proxy classes can be generated at runtime.
These proxy classes use reflection to forward the calls to a previously configured handler class.

## DP1
[//]: # (MAIN: dp.Main)
Tests the dynamic proxy API by implementing the ```dp.DebugProxy``` class that implements ```java.lang.reflect.Invocationhandler```
and provides a ```newInstance``` method that can than be used to instantiate a dynamic proxy object.
```dp.DebugProxy``` is then used in ```dp.Main```'s main method to instantiate a proxy object of the
```dp.FooImpl``` class and then calls a method on it.
```java
// dp/Foo.java
package dp;

public interface Foo { Object bar(Object obj); }
```
```java
// dp/FooImpl.java
package dp;

public class FooImpl implements Foo {
public Object bar(Object obj) {
return obj;
}
}
```
```java
// dp/DebugProxy.java
package dp;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;

public class DebugProxy implements InvocationHandler {
private Object obj;

public static Object newInstance(Object obj) {
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),
new DebugProxy(obj));
}

private DebugProxy(Object obj) { this.obj = obj; }

public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
System.out.println("before method " + m.getName());
return m.invoke(obj, args);
}
}
```
```java
// dp/Main.java
package dp;

import java.lang.reflect.Method;
import lib.annotations.callgraph.IndirectCall;

public class Main {
@IndirectCall(
name = "bar", returnType = Object.class, parameterTypes = Object.class, line = 17,
resolvedTargets = "Ldp/FooImpl;"
)
@IndirectCall(
name = "invoke", returnType = Object.class, parameterTypes = {Object.class, Method.class, Object[].class}, line = 17,
resolvedTargets = "Ldp/DebugProxy;"
)
public static void main(String[] args) {
Foo foo = (Foo) DebugProxy.newInstance(new FooImpl());
foo.bar(null);
}
}
```
[//]: # (END)
Loading

0 comments on commit 4f303c8

Please sign in to comment.