Skip to content

Commit 3d4183a

Browse files
Add ability to overlay classes with new definitions of existing methods
Allows multiple definitions of the same class to appear on the classpath, so long as all but the first definition are marked with the attribute @java::com.diffblue.security.OverlayClassImplementation. Overlay class definitions can contain methods with the same signature as methods in the original class, so long as these are marked with the attribute @java::com.diffblue.security.OverlayMethodImplementation; such overlay methods are replaced in the original file with the version found in the last overlay on the classpath. Later definitions can also contain new supporting methods and fields that are merged in. This will allow insertion of Java methods into library classes to handle, for example, modelling dependency injection. Includes regression tests Improvements over earlier version: Allows loading of classes such as java.lang.Object from an explicit model Prevent attempting to load any class more than once Invalid values in the classpath are ignored Handles duplicate files appearing in multiple items on the classpath Filter loaded class files to remove duplicates or misordered overlays before following links to other classes so as not to add dependencies of duplicate classes
1 parent dbc2f71 commit 3d4183a

32 files changed

+842
-263
lines changed
228 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public class Test {
2+
public void main() {}
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
Test.class
3+
--classpath ./NotHere.jar
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
^the program has no entry point$
7+
^failed to load class `Test'$
8+
--
9+
--
10+
symex-driven lazy loading should emit "the program has no entry point" but currently doesn't
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
Test.class
3+
--classpath ./NotHere
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
^the program has no entry point$
7+
^failed to load class `Test'$
8+
--
9+
--
10+
symex-driven lazy loading should emit "the program has no entry point" but currently doesn't
583 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
public class Test
2+
{
3+
public int x;
4+
5+
public static void main(String[] args)
6+
{
7+
assert(false);
8+
}
9+
10+
public static void notOverlain()
11+
{
12+
assert(true);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.diffblue;
2+
3+
public @interface OverlayClassImplementation {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.diffblue;
2+
3+
public @interface OverlayMethodImplementation {
4+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import com.diffblue.OverlayClassImplementation;
2+
import com.diffblue.OverlayMethodImplementation;
3+
4+
@OverlayClassImplementation
5+
public class Test
6+
{
7+
public int x;
8+
9+
@OverlayMethodImplementation
10+
public static void main(String[] args)
11+
{
12+
assert(true);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CORE
2+
Test.class
3+
--classpath `./format_classpath.sh . annotations correct-overlay` --verbosity 10
4+
^Getting class `Test' from file \.[\\/]Test\.class$
5+
^Getting class `Test' from file correct-overlay[\\/]Test\.class$
6+
^Adding symbol from overlay class: field 'x'$
7+
^Adding symbol from overlay class: method 'java::Test\.<init>:\(\)V'$
8+
^Field definition for java::Test\.x already loaded from overlay class$
9+
^Adding symbol from overlay class: method 'java::Test\.main:\(\[Ljava/lang/String;\)V'$
10+
^Method java::Test\.<init>:\(\)V exists in an overlay class without being marked as an overlay and also exists in the underlying class
11+
^Adding symbol: method 'java::Test\.notOverlain:\(\)V'$
12+
^VERIFICATION SUCCESSFUL$
13+
^EXIT=0$
14+
^SIGNAL=0$
15+
--
16+
^Skipping class Test marked with OverlayClassImplementation but found before original definition$
17+
^Skipping duplicate definition of class Test not marked with OverlayClassImplementation$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CORE
2+
Test.class
3+
--classpath `./format_classpath.sh . annotations . correct-overlay` --verbosity 10
4+
^Getting class `Test' from file \.[\\/]Test\.class$
5+
^Getting class `Test' from file correct-overlay[\\/]Test\.class$
6+
^Skipping duplicate definition of class Test not marked with OverlayClassImplementation$
7+
^Adding symbol from overlay class: field 'x'$
8+
^Adding symbol from overlay class: method 'java::Test\.<init>:\(\)V'$
9+
^Field definition for java::Test\.x already loaded from overlay class$
10+
^Adding symbol from overlay class: method 'java::Test\.main:\(\[Ljava/lang/String;\)V'$
11+
^Method java::Test\.<init>:\(\)V exists in an overlay class without being marked as an overlay and also exists in the underlying class
12+
^Adding symbol: method 'java::Test\.notOverlain:\(\)V'$
13+
^VERIFICATION SUCCESSFUL$
14+
^EXIT=0$
15+
^SIGNAL=0$
16+
--
17+
^Skipping class Test marked with OverlayClassImplementation but found before original definition$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
unameOut="$(uname -s)"
4+
case "${unameOut}" in
5+
CYGWIN*) separator=";";;
6+
MINGW*) separator=";";;
7+
MSYS*) separator=";";;
8+
Windows*) separator=";";;
9+
*) separator=":"
10+
esac
11+
12+
echo -n `IFS=$separator; echo "$*"`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
Test.class
3+
--classpath `./format_classpath.sh annotations correct-overlay .` --verbosity 10
4+
^Getting class `Test' from file correct-overlay[\\/]Test\.class$
5+
^Getting class `Test' from file \.[\\/]Test\.class$
6+
^Skipping class Test marked with OverlayClassImplementation but found before original definition$
7+
^Adding symbol: field 'x'$
8+
^Adding symbol: method 'java::Test\.main:\(\[Ljava/lang/String;\)V'$
9+
^Adding symbol: method 'java::Test\.notOverlain:\(\)V'$
10+
^VERIFICATION FAILED$
11+
^EXIT=10$
12+
^SIGNAL=0$
13+
--
14+
^Skipping duplicate definition of class Test not marked with OverlayClassImplementation$
15+
^Adding symbol from overlay class
16+
exists in an overlay class without being marked as an overlay and also exists in the underlying class
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import com.diffblue.OverlayClassImplementation;
2+
import com.diffblue.OverlayMethodImplementation;
3+
4+
public class Test
5+
{
6+
@OverlayMethodImplementation
7+
public static void main(String[] args)
8+
{
9+
assert(false);
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
Test.class
3+
--classpath `./format_classpath.sh . annotations unmarked-overlay` --verbosity 10
4+
^Getting class `Test' from file \.[\\/]Test\.class$
5+
^Getting class `Test' from file unmarked-overlay[\\/]Test\.class$
6+
^Skipping duplicate definition of class Test not marked with OverlayClassImplementation$
7+
^Adding symbol: field 'x'$
8+
^Adding symbol: method 'java::Test\.main:\(\[Ljava/lang/String;\)V'$
9+
^Adding symbol: method 'java::Test\.notOverlain:\(\)V'$
10+
^VERIFICATION FAILED$
11+
^EXIT=10$
12+
^SIGNAL=0$
13+
--
14+
^Skipping class Test marked with OverlayClassImplementation but found before original definition$
15+
^Adding symbol from overlay class
16+
exists in an overlay class without being marked as an overlay and also exists in the underlying class
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package java.lang;
2+
3+
public class Object {
4+
public final Class<?> getClass() {
5+
return null;
6+
}
7+
8+
public int hashCode() { return 0; }
9+
10+
public boolean equals(Object obj) { return (this == obj); }
11+
12+
protected Object clone() throws CloneNotSupportedException {
13+
throw new CloneNotSupportedException();
14+
}
15+
16+
public String toString() { return "object"; }
17+
18+
public final void notify() {}
19+
20+
public final void notifyAll() {}
21+
22+
public final void wait(long timeout) throws InterruptedException {
23+
throw new InterruptedException();
24+
}
25+
26+
public final void wait(long timeout, int nanos) throws InterruptedException {
27+
wait(timeout);
28+
}
29+
30+
public final void wait() throws InterruptedException { wait(0); }
31+
32+
protected void finalize() throws Throwable { }
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
java/lang/Object.class
3+
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
^the program has no entry point$
7+
--
8+
^failed to add class symbol java::java\.lang\.Object$
9+
--
10+
symex-driven lazy loading should emit "the program has no entry point" but currently doesn't

src/java_bytecode/ci_lazy_methods.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ bool ci_lazy_methodst::operator()(
8585
reachable_classes.push_back(main_class);
8686
else
8787
reachable_classes = main_jar_classes;
88-
for(const auto &classname : reachable_classes)
88+
for(const irep_idt &class_name : reachable_classes)
8989
{
90-
const auto &methods=
91-
java_class_loader.class_map.at(classname).parsed_class.methods;
90+
const auto &methods =
91+
java_class_loader.get_original_class(class_name).parsed_class.methods;
9292
for(const auto &method : methods)
9393
{
94-
const irep_idt methodid="java::"+id2string(classname)+"."+
95-
id2string(method.name)+":"+
96-
id2string(method.descriptor);
94+
const irep_idt methodid =
95+
"java::" + id2string(class_name) + "." + id2string(method.name)
96+
+ ":" + id2string(method.descriptor);
9797
method_worklist2.push_back(methodid);
9898
}
9999
}

0 commit comments

Comments
 (0)