Skip to content

Commit a8ff14b

Browse files
authored
Merge pull request #151 from secure-software-engineering/feature/sootup-test-setup
Add test setup for SootUp
2 parents a4a5aa1 + abc5db8 commit a8ff14b

File tree

17 files changed

+501
-412
lines changed

17 files changed

+501
-412
lines changed

.github/workflows/maven.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ on:
1212
jobs:
1313
BuildAndTest:
1414
strategy:
15+
fail-fast: false
1516
matrix:
16-
framework: [Soot, Opal] # TODO Add SootUp when available
17+
framework: [Soot, SootUp, Opal]
1718
runs-on: ubuntu-latest
1819
steps:
1920
- name: Checkout source code

boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@
1414
*/
1515
package test.cases.statics;
1616

17+
import java.util.List;
1718
import org.junit.Test;
1819
import test.core.AbstractBoomerangTest;
1920

2021
public class SimpleSingletonTest extends AbstractBoomerangTest {
2122

2223
private final String target = SimpleSingletonTarget.class.getName();
2324

25+
@Override
26+
public List<String> getIncludedPackages() {
27+
return List.of("java.lang.Runnable");
28+
}
29+
2430
@Test
2531
public void singletonDirect() {
2632
analyze(target, testName.getMethodName());

boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.LinkedHashSet;
4545
import java.util.Set;
4646
import java.util.stream.Collectors;
47+
import org.junit.After;
4748
import org.junit.Assert;
4849
import org.junit.Rule;
4950
import org.junit.rules.TestName;
@@ -74,7 +75,7 @@ public class AbstractBoomerangTest extends TestingFramework {
7475

7576
/**
7677
* Fails the test cases, when Boomerang's result set contains any object that does not inherit
77-
* from {@link test.core.selfrunning.AllocatedObject}.
78+
* from {@link AllocatedObject}.
7879
*/
7980
private static final boolean TRACK_IMPLICIT_IMPRECISE = false;
8081

@@ -371,4 +372,9 @@ private void checkContainsAllExpectedAccessPath(Set<AccessPath> allAliases) {
371372
Assert.fail("Did not find all access path! " + expected);
372373
}
373374
}
375+
376+
@After
377+
public void cleanUp() {
378+
super.cleanUp();
379+
}
374380
}

boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class OpalPhantomMethod private (
7272
case _ => false
7373
}
7474

75-
override def toString: String = s"PHANTOM: ${declaringClassType.toJava} $name"
75+
override def toString: String = s"PHANTOM: ${descriptor.toJava}"
7676
}
7777

7878
object OpalPhantomMethod {

boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import sootup.core.jimple.basic.*;
2323
import sootup.core.jimple.common.constant.ClassConstant;
2424
import sootup.core.jimple.common.constant.Constant;
25+
import sootup.core.jimple.common.constant.NullConstant;
2526
import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr;
2627
import sootup.core.jimple.common.expr.AbstractInvokeExpr;
2728
import sootup.core.jimple.common.expr.JStaticInvokeExpr;
@@ -30,13 +31,20 @@
3031
import sootup.core.jimple.common.ref.JStaticFieldRef;
3132
import sootup.core.jimple.common.stmt.*;
3233
import sootup.core.model.Body;
34+
import sootup.core.model.SootClass;
35+
import sootup.core.model.SootClassMember;
36+
import sootup.core.model.SootField;
37+
import sootup.core.signatures.FieldSignature;
3338
import sootup.core.transform.BodyInterceptor;
39+
import sootup.core.types.ClassType;
40+
import sootup.core.types.ReferenceType;
3441
import sootup.core.views.View;
3542

3643
public class BoomerangPreInterceptor implements BodyInterceptor {
3744

3845
private final boolean TRANSFORM_CONSTANTS_SETTINGS;
3946

47+
private static final String CONSTRUCTOR = "<init>";
4048
private static final String LABEL = "varReplacer";
4149
private int replaceCounter = 0;
4250

@@ -52,6 +60,10 @@ public BoomerangPreInterceptor(boolean transformConstantsSettings) {
5260
public void interceptBody(Body.@NonNull BodyBuilder bodyBuilder, @NonNull View view) {
5361
addNopStatementsToMethod(bodyBuilder);
5462

63+
if (bodyBuilder.getMethodSignature().getName().equals(CONSTRUCTOR)) {
64+
addNullifiedFields(bodyBuilder, view);
65+
}
66+
5567
if (TRANSFORM_CONSTANTS_SETTINGS) {
5668
transformConstantsAtFieldWrites(bodyBuilder);
5769
}
@@ -244,4 +256,83 @@ private boolean isFieldRef(Value value) {
244256
|| value instanceof JStaticFieldRef
245257
|| value instanceof JArrayRef;
246258
}
259+
260+
private void addNullifiedFields(Body.BodyBuilder bodyBuilder, View view) {
261+
ClassType classType = bodyBuilder.getMethodSignature().getDeclClassType();
262+
Optional<? extends SootClass> sootClass = view.getClass(classType);
263+
264+
if (sootClass.isEmpty()) {
265+
return;
266+
}
267+
268+
Collection<FieldSignature> allFields =
269+
sootClass.get().getFields().stream()
270+
.map(SootClassMember::getSignature)
271+
.collect(Collectors.toSet());
272+
Collection<FieldSignature> definedFields = getDefinedFields(bodyBuilder);
273+
274+
for (FieldSignature fieldSignature : allFields) {
275+
if (definedFields.contains(fieldSignature)) {
276+
continue;
277+
}
278+
279+
Optional<? extends SootField> field =
280+
sootClass.get().getField(fieldSignature.getSubSignature());
281+
if (field.isEmpty()) {
282+
continue;
283+
}
284+
285+
if (field.get().isStatic() || field.get().isFinal()) {
286+
continue;
287+
}
288+
289+
// TODO Consider only Ref types or all types?
290+
if (field.get().getType() instanceof ReferenceType) {
291+
JInstanceFieldRef nullifiedFieldRef =
292+
Jimple.newInstanceFieldRef(bodyBuilder.build().getThisLocal(), fieldSignature);
293+
JAssignStmt nullifiedFieldStmt =
294+
Jimple.newAssignStmt(
295+
nullifiedFieldRef,
296+
NullConstant.getInstance(),
297+
StmtPositionInfo.getNoStmtPositionInfo());
298+
299+
Optional<Stmt> firstNonIdentityStmt = findFirstNonIdentityStmt(bodyBuilder);
300+
if (firstNonIdentityStmt.isPresent()) {
301+
bodyBuilder.getStmtGraph().insertBefore(firstNonIdentityStmt.get(), nullifiedFieldStmt);
302+
} else {
303+
bodyBuilder.getStmtGraph().addNode(nullifiedFieldStmt);
304+
}
305+
}
306+
}
307+
}
308+
309+
private Collection<FieldSignature> getDefinedFields(Body.BodyBuilder bodyBuilder) {
310+
Collection<FieldSignature> definedFields = new LinkedHashSet<>();
311+
312+
for (Stmt stmt : bodyBuilder.getStmts()) {
313+
if (stmt instanceof JAssignStmt) {
314+
LValue leftOp = ((JAssignStmt) stmt).getLeftOp();
315+
316+
if (leftOp instanceof JInstanceFieldRef) {
317+
JInstanceFieldRef fieldRef = (JInstanceFieldRef) leftOp;
318+
319+
definedFields.add(fieldRef.getFieldSignature());
320+
}
321+
}
322+
}
323+
324+
return definedFields;
325+
}
326+
327+
private Optional<Stmt> findFirstNonIdentityStmt(Body.BodyBuilder bodyBuilder) {
328+
for (Stmt stmt : bodyBuilder.getStmts()) {
329+
if (stmt instanceof JIdentityStmt) {
330+
continue;
331+
}
332+
333+
return Optional.of(stmt);
334+
}
335+
336+
return Optional.empty();
337+
}
247338
}

boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpCallGraph.java

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
import boomerang.scope.CallGraph;
1818
import boomerang.scope.Statement;
1919
import boomerang.scope.sootup.jimple.JimpleUpMethod;
20+
import boomerang.scope.sootup.jimple.JimpleUpPhantomMethod;
2021
import boomerang.scope.sootup.jimple.JimpleUpStatement;
2122
import java.util.Collection;
2223
import java.util.Optional;
24+
import sootup.core.jimple.common.expr.AbstractInvokeExpr;
25+
import sootup.core.jimple.common.expr.JStaticInvokeExpr;
2326
import sootup.core.jimple.common.stmt.InvokableStmt;
2427
import sootup.core.signatures.MethodSignature;
2528
import sootup.java.core.JavaSootMethod;
@@ -38,17 +41,13 @@ public SootUpCallGraph(
3841
.flatMap((MethodSignature methodSignature) -> callGraph.callsTo(methodSignature).stream())
3942
.forEach(
4043
call -> {
41-
// TODO Integrate Phantom methods
4244
Optional<JavaSootMethod> sourceOpt = view.getMethod(call.getSourceMethodSignature());
43-
Optional<JavaSootMethod> targetOpt = view.getMethod(call.getTargetMethodSignature());
44-
45-
if (sourceOpt.isEmpty() || targetOpt.isEmpty()) {
45+
if (sourceOpt.isEmpty()) {
4646
return;
4747
}
4848

4949
JavaSootMethod sourceMethod = sourceOpt.get();
50-
JavaSootMethod targetMethod = targetOpt.get();
51-
if (!sourceMethod.hasBody() || !targetMethod.hasBody()) {
50+
if (!sourceMethod.hasBody()) {
5251
return;
5352
}
5453

@@ -59,9 +58,31 @@ public SootUpCallGraph(
5958

6059
Statement callSite =
6160
JimpleUpStatement.create(invokableStmt, JimpleUpMethod.of(sourceMethod, view));
62-
this.addEdge(new Edge(callSite, JimpleUpMethod.of(targetMethod, view)));
6361

64-
LOGGER.trace("Added edge {} -> {}", callSite, targetMethod);
62+
MethodSignature targetSig = call.getTargetMethodSignature();
63+
Optional<JavaSootMethod> targetOpt = view.getMethod(targetSig);
64+
65+
Optional<AbstractInvokeExpr> invokeExprOpt = invokableStmt.getInvokeExpr();
66+
if (invokeExprOpt.isEmpty()) {
67+
return;
68+
}
69+
70+
boolean isStaticInvokeExpr = invokeExprOpt.get() instanceof JStaticInvokeExpr;
71+
if (targetOpt.isPresent()) {
72+
if (targetOpt.get().hasBody()) {
73+
this.addEdge(new Edge(callSite, JimpleUpMethod.of(targetOpt.get(), view)));
74+
} else {
75+
this.addEdge(
76+
new Edge(
77+
callSite, JimpleUpPhantomMethod.of(targetSig, view, isStaticInvokeExpr)));
78+
}
79+
} else {
80+
this.addEdge(
81+
new Edge(
82+
callSite, JimpleUpPhantomMethod.of(targetSig, view, isStaticInvokeExpr)));
83+
}
84+
85+
LOGGER.trace("Added edge {} -> {}", callSite, targetSig);
6586
});
6687

6788
for (JavaSootMethod m : entryPoints) {
@@ -71,7 +92,7 @@ public SootUpCallGraph(
7192
}
7293
}
7394

74-
if (getEdges().isEmpty()) {
95+
if (getEdges().isEmpty() && entryPoints.isEmpty()) {
7596
throw new IllegalStateException("CallGraph is empty!");
7697
}
7798
}

boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,15 @@ public boolean equals(Object o) {
6060
if (o == null || getClass() != o.getClass()) return false;
6161
if (!super.equals(o)) return false;
6262
JimpleUpField that = (JimpleUpField) o;
63-
return Objects.equals(delegate, that.delegate);
63+
// Important: Do not include the declaring class because subclasses may access the field, too
64+
return Objects.equals(delegate.getType(), that.delegate.getType())
65+
&& Objects.equals(delegate.getName(), that.delegate.getName());
6466
}
6567

6668
@Override
6769
public int hashCode() {
68-
return Objects.hash(super.hashCode(), delegate);
70+
// Important: Do not include the declaring class because subclasses may access the field, too
71+
return Objects.hash(super.hashCode(), delegate.getType(), delegate.getName());
6972
}
7073

7174
@Override

boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpPhantomMethod.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,29 @@
2323
import java.util.ArrayList;
2424
import java.util.List;
2525
import java.util.Objects;
26-
import sootup.java.core.JavaSootMethod;
26+
import sootup.core.signatures.MethodSignature;
2727
import sootup.java.core.views.JavaView;
2828

2929
public class JimpleUpPhantomMethod extends PhantomMethod {
3030

3131
protected static Interner<JimpleUpPhantomMethod> INTERNAL_POOL = Interners.newWeakInterner();
3232

33-
private final JavaSootMethod delegate;
33+
private final MethodSignature delegate;
3434
private final JavaView view;
35+
private final boolean isStatic;
3536

36-
protected JimpleUpPhantomMethod(JavaSootMethod delegate, JavaView view) {
37+
protected JimpleUpPhantomMethod(MethodSignature delegate, JavaView view, boolean isStatic) {
3738
this.delegate = delegate;
3839
this.view = view;
39-
40-
if (delegate.hasBody()) {
41-
throw new IllegalArgumentException("Cannot build phantom method from method with body");
42-
}
40+
this.isStatic = isStatic;
4341
}
4442

45-
public static JimpleUpPhantomMethod of(JavaSootMethod delegate, JavaView view) {
46-
return INTERNAL_POOL.intern(new JimpleUpPhantomMethod(delegate, view));
43+
public static JimpleUpPhantomMethod of(
44+
MethodSignature delegate, JavaView view, boolean isStatic) {
45+
return INTERNAL_POOL.intern(new JimpleUpPhantomMethod(delegate, view, isStatic));
4746
}
4847

49-
public JavaSootMethod getDelegate() {
48+
public MethodSignature getDelegate() {
5049
return delegate;
5150
}
5251

@@ -73,17 +72,17 @@ public Type getParameterType(int index) {
7372

7473
@Override
7574
public Type getReturnType() {
76-
return new JimpleUpType(delegate.getReturnType(), view);
75+
return new JimpleUpType(delegate.getType(), view);
7776
}
7877

7978
@Override
8079
public boolean isStatic() {
81-
return delegate.isStatic();
80+
return isStatic;
8281
}
8382

8483
@Override
8584
public WrappedClass getDeclaringClass() {
86-
return new JimpleUpWrappedClass(delegate.getDeclaringClassType(), view);
85+
return new JimpleUpWrappedClass(delegate.getDeclClassType(), view);
8786
}
8887

8988
@Override
@@ -116,6 +115,6 @@ public int hashCode() {
116115

117116
@Override
118117
public String toString() {
119-
return delegate.toString();
118+
return "PHANTOM:" + delegate.toString();
120119
}
121120
}

boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStaticFieldRef.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ public boolean equals(Object o) {
8282
if (o == null || getClass() != o.getClass()) return false;
8383
if (!super.equals(o)) return false;
8484
JimpleUpStaticFieldRef that = (JimpleUpStaticFieldRef) o;
85-
return Objects.equals(delegate, that.delegate);
85+
// TODO
86+
// Wrong equals implementation in SootUp. Once fixed, replace this with
87+
// the commented line
88+
return (delegate != null && delegate.equals(that.delegate));
89+
// return Objects.equals(delegate, that.delegate);
8690
}
8791

8892
@Override

0 commit comments

Comments
 (0)