Skip to content

Commit 50f4846

Browse files
committed
Merge branch 'develop' into ci/snapshotrelease
# Conflicts: # .github/workflows/documentation-branch-snapshot.yml # pom.xml
2 parents e94ad4d + 1356f9f commit 50f4846

37 files changed

+1839
-97
lines changed

.gitattributes

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Documentation Deployment
2+
3+
on:
4+
push:
5+
branches:
6+
- develop
7+
tags:
8+
- '*'
9+
10+
concurrency:
11+
group: gh-pages
12+
13+
jobs:
14+
# On push/merge to develop: Deploy the current doc as default/latest
15+
deploy-doc-snapshots:
16+
name: Deploy Snapshot Documentation
17+
if: ${{ github.event_name == 'push' }}
18+
runs-on: ubuntu-latest
19+
permissions:
20+
contents: write
21+
22+
steps:
23+
- name: Checkout Repository
24+
uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0
27+
28+
- name: Extract Maven Version
29+
id: version
30+
run: |
31+
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
32+
echo "version=$VERSION" >> $GITHUB_OUTPUT
33+
34+
- name: Deploy Snapshot Documentation
35+
uses: secure-software-engineering/actions/documentation/handle-deployment@develop
36+
with:
37+
name: ${{ steps.version.outputs.version }}
38+
title: ${{ steps.version.outputs.version }}
39+
40+
# On tag creation (i.e. new release): Deploy a stable version to directory with tag
41+
deploy-doc-stable:
42+
name: Deploy Stable Documentation
43+
if: startsWith(github.ref, 'refs/tags/')
44+
runs-on: ubuntu-latest
45+
permissions:
46+
contents: write
47+
48+
steps:
49+
- name: Checkout Repository
50+
uses: actions/checkout@v4
51+
with:
52+
ref: ${{ github.ref }}
53+
fetch-depth: 0
54+
55+
- name: Deploy Stable Documentation
56+
uses: secure-software-engineering/actions/documentation/handle-deployment@develop
57+
with:
58+
name: ${{ github.ref_name }}
59+
title: ${{ github.ref_name }}
60+
stable: true

.github/workflows/doc_preview.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Documentation Preview
2+
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- closed
8+
- synchronize
9+
- reopened
10+
paths:
11+
- mkdocs.yml
12+
- docs/**
13+
- .github/workflows/doc_preview.yml
14+
15+
concurrency:
16+
group: gh-pages
17+
18+
jobs:
19+
deploy-preview:
20+
name: Preview documentation
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: write
24+
pull-requests: write
25+
26+
steps:
27+
- name: Checkout Repository
28+
uses: actions/checkout@v4
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Create Documentation Preview
33+
uses: secure-software-engineering/actions/documentation/handle-pr-preview@develop
34+
with:
35+
preview-name: pr-${{ github.event.pull_request.number }}
36+
preview-title: Preview for PR-${{ github.event.pull_request.number }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ shippable/
1111
*.prefs
1212
*.xml
1313
**/target
14+
**/site

docs/boomerang/allocation_sites.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Defining Allocation Sites
2+
3+
Boomerang provides an interface that allows the definition of individual allocation sites. An allocation site is a value that should be considered as a points-to object.
4+
5+
6+
## Allocation Site Interface
7+
8+
To define an individual allocation site, we have to implement the `IAllocationSite` interface and override its method `getAllocationSite(...)` that returns an optional `AllocVal`.
9+
An `AllocVal` represents an allocation site and acts as a wrapper for the allocation site statement and value.
10+
If the optional is present, the `AllocVal` is added to the resulting allocation sites.
11+
12+
When performing a backward analysis, Boomerang calls this method on each statement on each data-flow path.
13+
It provides three parameters to the method `getAllocationSite`:
14+
15+
- Method: The current method
16+
- Statement: The current statement that may contain an allocation site
17+
- Val: The current propagated data-flow fact
18+
19+
These parameters necessitate two checks that should be part of each allocation site implementation:
20+
21+
- Check whether the statement is an assignment
22+
- Check whether the left operand of the assignment is equal to the propagated data-flow fact
23+
24+
The first point is relevant because an allocation site is defined as an assignment.
25+
The second aspect is relevant to avoid returning statements that are not relevant to the points-to analysis.
26+
Boomerang propagates only data-flow facts that are relevant to or alias with the query variable.
27+
Therefore, one can exclude irrelevant assignments with the second check.
28+
29+
To this end, a self-defined allocation site should have at least the following code:
30+
31+
```java
32+
public class ExtendedAllocationSite implements IAllocationSite {
33+
34+
@Override
35+
public Optional<AllocVal> getAllocationSite(Method method, Statement statement, Val fact) {
36+
// Check for assignments
37+
if (!statement.isAssignStmt()) {
38+
return Optional.empty();
39+
}
40+
41+
Val leftOp = statement.getLeftOp();
42+
Val rightOp = statement.getRightOp();
43+
// Check for correct data-flow fact
44+
if (!leftOp.equals(fact)) {
45+
return Optional.empty();
46+
}
47+
48+
// rightOp is a potential allocation site
49+
...
50+
}
51+
}
52+
```
53+
54+
Last, to use our self-defined allocation site, we need to add it to the options:
55+
56+
```java
57+
BoomerangOptions options =
58+
BoomerangOptions.builder()
59+
.withAllocationSite(new ExtendedAllocationSite())
60+
...
61+
.build();
62+
```
63+
64+
## Simple Allocation Site
65+
66+
To show how an implementation of the `IAllocationSite` interface may look like, we consider the following simple example:
67+
68+
Assume our program requires *constants* and *new expressions* as allocation sites.
69+
Then, the interface implementation may look like this:
70+
71+
```java
72+
public class SimpleAllocationSite implements IAllocationSite {
73+
74+
@Override
75+
public Optional<AllocVal> getAllocationSite(Method method, Statement statement, Val fact) {
76+
// Check for assignments
77+
if (!statement.isAssignStmt()) {
78+
return Optional.empty();
79+
}
80+
81+
Val leftOp = statement.getLeftOp();
82+
Val rightOp = statement.getRightOp();
83+
// Check for correct data-flow fact
84+
if (!leftOp.equals(fact)) {
85+
return Optional.empty();
86+
}
87+
88+
// Constant allocation sites: var = <constant>
89+
if (rightOp.isConstant()) {
90+
AllocVal allocVal = new AllocVal(leftOp, statement, rightOp);
91+
return Optional.of(allocVal);
92+
}
93+
94+
// New expressions: var = new java.lang.Object
95+
if (rightOp.isNewExpr()) {
96+
AllocVal allocVal = new AllocVal(leftOp, statement, rightOp);
97+
return Optional.of(allocVal);
98+
}
99+
100+
return Optional.empty();
101+
}
102+
}
103+
```
104+
105+
Using this allocation site implementation, Boomerang returns values that are either *new expressions* (e.g. `new java.lang.Object`) or *constants* (e.g. int, String etc.).
106+
107+
## Allocation Site with DataFlowScope
108+
109+
In many cases, we are interested in finding an allocation site to analyze it.
110+
However, a common scenario where Boomerang cannot find an allocation site occurs when a data-flow path ends because we have a function call that is not part of the application.
111+
For example, using the `SimpleAllocationSite` from the previous section, Boomerang would not find an allocation site in the following program:
112+
113+
```java
114+
String s = System.getProperty("property"); // Most precise allocation site
115+
...
116+
queryFor(s);
117+
```
118+
119+
Boomerang does not compute an allocation site because `System.getProperty("property")` is not a *constant* or a *new expression*.
120+
Additionally, we may be interested in analyzing only our own application, that is, we do not load the JDK class `java.lang.System` and exclude it in the `DataFlowScope`.
121+
In this case, Boomerang returns an empty results set because the data-flow path ends at the call `System.getProperty("property")`.
122+
123+
To cover these scenarios, we can include the `DataFlowScope` in the allocation site implementation.
124+
For example, we can extend the [DefaultAllocationSite](https://github.com/secure-software-engineering/Boomerang/blob/develop/boomerangPDS/src/main/java/boomerang/options/DefaultAllocationSite.java) as follows:
125+
126+
```java
127+
public class ExtendedDataFlowScope extends DefaultAllocationSite {
128+
129+
private final DataFlowScope dataFlowScope;
130+
131+
public ExtendedDataFlowScope(DataFlowScope dataFlowScope) {
132+
this.dataFlowScope = dataFlowScope;
133+
}
134+
135+
@Override
136+
public Optional<AllocVal> getAllocationSite(Method method, Statement statement, Val fact) {
137+
// Check for assignments
138+
if (!statement.isAssignStmt()) {
139+
return Optional.empty();
140+
}
141+
142+
Val leftOp = statement.getLeftOp();
143+
Val rightOp = statement.getRightOp();
144+
// Check for correct data-flow fact
145+
if (!leftOp.equals(fact)) {
146+
return Optional.empty();
147+
}
148+
149+
// Check for function calls that would end the data-flow path
150+
// If the function call is not excluded, Boomerang can continue with the analysis
151+
if (statement.containsInvokeExpr()) {
152+
InvokeExpr invokeExpr = statement.getInvokeExpr();
153+
DeclaredMethod declaredMethod = invokeExpr.getDeclaredMethod();
154+
155+
if (dataFlowScope.isExcluded(declaredMethod)) {
156+
// rightOp is the invoke expression
157+
AllocVal allocVal = new AllocVal(leftOp, statement, rightOp);
158+
return Optional.of(allocVal);
159+
}
160+
}
161+
162+
// If the statement does not contain a function call, we continue with the default behavior
163+
return super.getAllocationSite(method, statement, fact);
164+
}
165+
}
166+
```
167+
168+
With this implementation, we cover function calls that would end the analysis, and we can conclude that the allocation site cannot be computed precisely.
169+
For example, having `System.getProperty("property")` as allocation site indicates that the query variable points to some object that depends on some system variables at runtime.

docs/boomerang/boomerang_setup.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Boomerang Setup
2+
3+
Boomerang's purpose is the computation of points-to information for a variable on-demand.
4+
Starting at a specific statement, it traverses the program and its data-flow paths backwards until it finds an allocation site for the desired variable.
5+
While doing that, it computes relevant alias information.
6+
7+
In the following sections, we give an overview of relevant constructs and API calls.
8+
We highly recommend to take a look at the examples to see the best way to combine these constructs.
9+
10+
## Backward Queries
11+
12+
Boomerang uses *backward queries* to compute relevant points-to information.
13+
A **BackwardQuery** consists of a statement `s` and a variable `v`. `s` is the starting statement where the backwards analysis starts and `v` is the data-flow fact to solve for.
14+
15+
Backward queries can be easily constructed.
16+
However, due to Boomerang's scope implementation, we need to specify the corresponding control-flow graph edge with the starting statement `s` as target (see the [Boomerang Scopes](./../general/boomerang_scope.md)).
17+
With that, we can construct a backward query as follows:
18+
19+
```java
20+
public void createBackwardQuery(ControlFlowGraph.Edge, edge, Val fact) {
21+
BackwardQuery query = BackwardQuery.make(edge, fact);
22+
}
23+
```
24+
25+
## Running Boomerang
26+
27+
Boomerang requires a [FrameworkScope](./../general/framework_scopes.md) and a set [Options](./../boomerang/options.md). With that, we can solve a backward query as follows:
28+
29+
```java
30+
public void solveQuery(
31+
BackwardQuery query,
32+
FrameworkScope scope,
33+
BoomerangOptions options) {
34+
Boomerang solver = new Boomerang(scope, options);
35+
BackwardBoomerangResults<NoWeight> results = solver.solve(query);
36+
}
37+
```
38+
39+
The call to `solve` solves the query and returns a wrapper for the results.
40+
41+
!!! Important:
42+
A `Boomerang` instance can be used to solve exactly one query.
43+
If you want to solve multiple queries with the same instance, you have to set [allowMultipleQueries]() in the options to `true` and you have to call `unregisterAllListeners()` after each call to `solve`.
44+
This may look like this:
45+
46+
```java
47+
public void solveQueries(
48+
Collection<BackwardQuery> queries,
49+
FrameworkScope scope,
50+
BoomerangOptions options) {
51+
Boomerang solver = new Boomerang(scope, options);
52+
53+
for (BackwardQuery query : queries) {
54+
BackwardBoomerangResults<NoWeight> results = solver.solve(query);
55+
// <Process or store the results>
56+
solver.unregisterAllListeners();
57+
}
58+
}
59+
```
60+
61+
## Extracting Allocation Sites
62+
63+
After running Boomerang, we can use the results to compute the allocation sites, i.e. the objects the query variable points to. An allocation site `AllocVal` is wrapped into a `ForwardQuery` object. Note that the computed allocation sites heavily depend on the used [AllocationSite](./../boomerang/allocation_sites.md) definition. We can extract the corresponding `AllocVal` objects as follows:
64+
65+
```java
66+
public void extractAllocationSites(BackwardBoomerangResults<NoWeight> results) {
67+
// Compute the allocation sites
68+
Collection<ForwardQuery> allocationSites = results.getAllocationSites().keySet();
69+
70+
for (ForwardQuery query : allocationSites) {
71+
// This is a single allocation site
72+
AllocVal allocVal = query.getAllocVal();
73+
System.out.println(
74+
"Query variable points to "
75+
+ allocVal.getAllocVal()
76+
+ " @ statement"
77+
+ allocVal.getAllocStatement()
78+
+ " @ line "
79+
+ allocVal.getAllocStatement().getLineNumber()
80+
+ " in method "
81+
+ allocVal.getAllocStatement().getMethod());
82+
}
83+
}
84+
```
85+
86+
## Extracting Aliases
87+
88+
Beside the allocation sites, we can use the results to compute the aliases for the query variable. An alias is represented by an `AccessPath` that holds the base variable and the field chain. For example, an alias `x.f.g` is represented by an `AccessPath` with the base `x` and the field chain `[f, g]`. We can compute the access paths as follows:
89+
90+
```java
91+
public void extractAliases(BackwardBoomerangResults<NoWeight> results) {
92+
Collection<AccessPath> aliases = results.getAllAliases();
93+
94+
System.out.println("Found the following aliases:")
95+
for (AccessPath alias : aliases) {
96+
// 'toCompactString()' transforms the access path into a basic String, e.g. x.f.g
97+
System.out.println(alias.toCompactString());
98+
}
99+
100+
}
101+
```
102+
103+
// TODO Aliases at specific statement

docs/boomerang/options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Boomerang Options

docs/examples.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)