Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix ci: gh pages #778

Merged
merged 12 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,19 @@ on:
concurrency: pages

permissions:
pages: write
contents: write
pull-requests: write
pages: write # to trigger a gh-pages build
deployments: write
contents: write # for creating files via mike/mkdocs
pull-requests: write # for commenting the link

jobs:
manage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# to get tag information
- run: git fetch --prune --unshallow
- uses: actions/checkout@v3
with:
fetch-depth: 0
fetch-tags: true # to get tag information

- uses: actions/setup-python@v2
with:
Expand Down Expand Up @@ -72,12 +74,12 @@ jobs:
# on push to develop branch - keep a doc around for develop to show the current state
- name: deploy doc in subdirectory
if: github.event_name == 'push'
run: mike deploy develop
run: mike deploy develop --push

# on PR events..
- name: deploy doc in subdirectory
if: github.event_name == 'pull_request'
run: mike deploy ${{ env.DOC_VERSION_NAME }}_preview -t "PR Preview ${{ env.DOC_VERSION_NAME }}" && mike props ${{ env.DOC_VERSION_NAME }}_preview --set-string hidden=true --push
run: mike deploy ${{ env.DOC_VERSION_NAME }}_preview -t "PR Preview ${{ env.DOC_VERSION_NAME }}" --push && mike props ${{ env.DOC_VERSION_NAME }}_preview --set-string hidden=true --push

- name: comment link to preview
if: github.event_name == 'pull_request' && github.event.action != 'closed'
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ A complete overhaul of the good, old static analysis framework [Soot](https://gi
- Provides ClassHierarchy generation
- CallGraph generation with different algorithms/precisions
- Inter-procedural Data-flow Analysis with the IDE/IFDS framework enabled by [Heros](https://github.com/Sable/heros)
- Applies/Enables simple transformations on retrieving a methods Body (see BodyInterceptor)
- Provides serialization of the Jimple IR.
- Applies simple transformations on retrieving a methods Body (see `BodyInterceptor`)
- Provides parsing and serialization of the Jimple IR.

## Getting started
[Documentation](https://soot-oss.github.io/SootUp/) and usage examples are available on Github pages.
Expand All @@ -23,13 +23,13 @@ Do you have questions? Feel free to start a [Discussion](https://github.com/soot

## SootUp improvements
#### (compared to its predecessor [Soot](https://github.com/soot-oss/soot).)
- [x] New Improved API (without Globals/Singletons)
- [x] New improved API (without Globals/Singletons)
- [x] Fully-Parallelizable Architecture
- [x] Enables lazyloading of classes (no interleaved loading of used/dependent classes anymore)
- [x] Enables lazy loading of classes (no interleaved loading of used/dependent classes anymore)
- [x] Fail early strategy - input validation while constructing/building objects
- [x] Up-to-Date (i.e. Java8!) Sourcecode Frontend
- [x] Up-to-Date (i.e. Java8!) Sourcecode Frontend (Beware: Cannot handle try-catch inputs, yet!)
- [x] Full Java 21 Support for Bytecode
- [x] Multiple Views (Scenes)
- [x] Multiple Views (no single static Scene anymore)
- [x] Immutable Jimple IR Objects and Graphs
- [ ] Incremental Updates of Program Representation

Expand Down
164 changes: 1 addition & 163 deletions docs/advanced-topics.md
Original file line number Diff line number Diff line change
@@ -1,166 +1,4 @@
# Advanced Topics

As a user of the SootUp framework, you can omit these topics which mostly explain how some of the concepts work internally.

## Body Interceptors

!!! info "Soot Equivalent"

[BodyTransformer](https://github.com/soot-oss/soot/blob/develop/src/main/java/soot/BodyTransformer.java)


Almost in all use-cases you can simply *ignore* body interceptors. They are applied to each `Body` *by default* to create their rather normalized or leaner versions, e.g.
by eliminating unreachable code (`UnreachableCodeEliminator`), standardizing names of locals (`LocalNameStandardizer`), or removing empty switch statements (`EmptySwitchEliminator`) etc.

Below, we show how these body interceptors work for the users who are interested in their internal workings.

### LocalSplitter

LocalSplitter is a<code>BodyInterceptor</code>that attempts to identify and separate uses of a local variable (as definition) that are independent of each other by renaming local variables.

Example 1:

![LocalSplitter Example_1](./figures/LocalSplitter%20Example_1.png)

As shown in the example above, the local variable<code>l1</code>is defined twice. It can be split up into two new local variables: <code>l1#1</code> and <code>l1#2</code> because the both definitions are independent of each other.



Look for foldable navigation and tabs for showing old vs new


Example 2:

![LocalSplitter Example_2](./figures/LocalSplitter%20Example_2.png)

In the second example, the local variable<code>l2</code>is defined thrice. But it cannot be split up into three new local variables as in the first example, because its definitions in the if-branches are not independent of each other. Therefore, it can only be split up into two local variables as shown in the figure.



### LocalPacker

LocalPacker is a<code>BodyInterceptor</code>that attempts to minimize the number of local variables which are used in body by reusing them, when it is possible. It corresponds to the inverse body transformation of LocalSplitter. Note: Every local variable's type should be assigned before running LocalPacker.

Example:

![LocalPacker Example](./figures/LocalPacker%20Example.png)

In the given example above, the local variables<code>l1</code>,<code>l3</code>are summarized to be one local variable<code>l1</code>, because they have the same type without interference with each other. Likewise, the local variables<code>l2</code>,<code>l4</code>and<code>l5</code>are summarized to be another local variable<code>l2</code>. Although the local variable<code>l0</code>doesn't interfere any other local variables, it cannot be summed up with other local variables because of its distinctive type.



### TrapTightener

TrapTightener is a<code>BodyInterceptor</code>that shrinks the protected area covered by each Trap in a Body.

Example:

![TrapTightener Example](./figures/TrapTightener%20Example.png)

We assume in the example above that only the<code>Stmt</code>:<code>l2 := 2</code>might throw an exception caught by the<code>Trap</code>which is labeled with<code>label3</code>. In the jimple body before running the TrapTightener, the protected area covered by the Trap contains three<code>Stmts</code>:<code>l1 := 1; l2 := 2; l2 := 3</code>. But an exception could only arise at the<code>Stmt</code>:<code>l2 := 2</code>. After the implementation of TrapTightener, we will get a contractible protected area which contains only the<code>Stmt</code>that might throw an exception, namely the<code>Stmt</code>:<code>l2 := 2</code>.



### EmptySwitchEliminator

EmptySwitchEliminator is a<code>BodyInterceptor</code>that removes empty switch statements which contain only the default case.

Example:

![EmptySwitchEliminator Example](./figures/EmptySwitchEliminator%20Example.png)

As shown in the example above, the switch statement in the jimple body always takes the default action. After running EmptySwitchEliminator, the switch statement is replaced with a<code>GotoStmt</code>to the default case.



### UnreachableCodeEliminator

UnreachableCodeEliminator is a<code>BodyInterceptor</code>that removes all unreachable statements.

Example:

![UnreachableCodeEliminator Example](./figures/UnreachableCodeEliminator%20Example.png)

Obviously, the code segment<code>l2 = 2; l3 = 3;</code>is unreachable. It will be removed after running the UreachableCodeEliminator.



### CopyPropagator

CopyPropagator is a<code>BodyInterceptor</code>that supports the global copy propagation and constant propagation.

Example for global copy propagation:

![UnreachableCodeEliminator Example](./figures/CopyPropagator%20Example_1.png)

Consider a code segment in the following form:

```
a = b;
...
c = use(a); // a, b, c are local variables
```

According to the copy propagation's definition, the statement<code>c = use(a)</code>can be replaced with<code>c = use(b)</code>iff both conditions are met:

* <code>a</code>is defined only one time on all the paths from<code>a = b</code>to<code>c = use(a)</code>.
* There are no definitions of<code>b</code>on any path from<code>a = b</code>to<code>c = use(a)</code>.

In the example for global copy propagation, the first used<code>l1</code>is replaced with<code>l0</code>, but the second used<code>l1</code>cannot be replaced with<code>l3</code>, because the second condition is not satisfied.

Example for constant propagation:

![CopyPropagator Example_1](figures/CopyPropagator%20Example_2.png)

Constant propagation is similar to copy propagation. Consider a code segment in the following form:

```
a = const;
...
b = use(a); // a, b are local variables, const is a constant
```

After perfoming the constant propagation, the statement<code>b = use(a)</code>can be replaced with<code>b = use(const)</code>iff<code>a</code>is not redefined on any of the paths from<code>a = const</code>to<code>b = use(a)</code>.

Therefore, the first used<code>l1</code>in the second example can be replaced with the constant<code>1</code>, but the second used<code>l1</code>cannot be replaced with the constant<code>2</code>, because<code>l1</code>is redefined on the path from<code>l1 = 2</code>to<code>l4 = use(l1)</code>. However, it can be replaced with local variable<code>l2</code>, because the both conditions of copy propagation are met.

### LocalNameStandardizer

LocalNameStandardizer is a<code>BodyInterceptor</code>that assigns a generic name to each local variable. Firstly, it will sort the local variables' order alphabetically by the string representation of their type. If there are two local variables with the same type, then the LocalNameStandardizer will use the sequence of their occurrence in jimple body to determine their order. Each assigned name consists of two parts:

* A letter to imply the local variable's type
* A digit to imply the local variable's order

The following table shows the letter corresponding to each type:

| Type of Local Variable | Letter |
| :---------------: | :---------: |
| boolean | z |
| byte | b |
| short | s |
| int | i |
| long | l |
| float | f |
| double | d |
| char | c |
| null | n |
| unknown | e |
| reference | r |


### StaticSingleAssignmentFormer

StaticSingleAssignmentFormer is a<code>BodyInterceptor</code>that transforms jimple body into SSA form, so that each local variable is assigned exactly once and defined before its first use.

Example:

![SSA Example_1](./figures/SSA%20Example_1.png)

![SSA Example_2](./figures/SSA%20Example_2.png)

In the given example, the StaticSingleAssignmentFormer assigns each<code>IdentityStmt</code>and<code>AssignStmt</code>to a new local variable . And each use uses the local variable which is most recently defined. Sometimes, it is impossible to determine the most recently defined local variable for a use in a join block. In this case, the StaticSingleAssignmentFormer will insert a<code>PhiStmt</code>in the front of the join block to merge all most recently defined local variables and assign them a new local variable.

## Tools
# Functionalities and Utilities

#### LocalLivenessAnalyser

Expand Down
158 changes: 158 additions & 0 deletions docs/bodyinterceptors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Body Interceptors

!!! info "Soot Equivalent"

[BodyTransformer](https://github.com/soot-oss/soot/blob/develop/src/main/java/soot/BodyTransformer.java)


BodyInterceptors are applied to each `Body` *by default* to improve or even normalize the raw Jimple that was produced in an earlier step e.g.
by eliminating unreachable code (`UnreachableCodeEliminator`), standardizing names of locals (`LocalNameStandardizer`), or removing empty switch statements (`EmptySwitchEliminator`) etc.

Below, we show how these BodyInterceptors work for the users who are interested in their internal workings.

### LocalSplitter

LocalSplitter is a<code>BodyInterceptor</code>that attempts to identify and separate uses of a local variable (as definition) that are independent of each other by renaming local variables.

Example 1:

![LocalSplitter Example_1](./figures/LocalSplitter%20Example_1.png)

As shown in the example above, the local variable<code>l1</code>is defined twice. It can be split up into two new local variables: <code>l1#1</code> and <code>l1#2</code> because the both definitions are independent of each other.



Look for foldable navigation and tabs for showing old vs new


Example 2:

![LocalSplitter Example_2](./figures/LocalSplitter%20Example_2.png)

In the second example, the local variable<code>l2</code>is defined thrice. But it cannot be split up into three new local variables as in the first example, because its definitions in the if-branches are not independent of each other. Therefore, it can only be split up into two local variables as shown in the figure.



### LocalPacker

LocalPacker is a<code>BodyInterceptor</code>that attempts to minimize the number of local variables which are used in body by reusing them, when it is possible. It corresponds to the inverse body transformation of LocalSplitter. Note: Every local variable's type should be assigned before running LocalPacker.

Example:

![LocalPacker Example](./figures/LocalPacker%20Example.png)

In the given example above, the local variables<code>l1</code>,<code>l3</code>are summarized to be one local variable<code>l1</code>, because they have the same type without interference with each other. Likewise, the local variables<code>l2</code>,<code>l4</code>and<code>l5</code>are summarized to be another local variable<code>l2</code>. Although the local variable<code>l0</code>doesn't interfere any other local variables, it cannot be summed up with other local variables because of its distinctive type.



### TrapTightener
**WIP - currently not available!**

TrapTightener is a<code>BodyInterceptor</code>that shrinks the protected area covered by each Trap in a Body.

Example:

![TrapTightener Example](./figures/TrapTightener%20Example.png)

We assume in the example above that only the<code>Stmt</code>:<code>l2 := 2</code>might throw an exception caught by the<code>Trap</code>which is labeled with<code>label3</code>. In the jimple body before running the TrapTightener, the protected area covered by the Trap contains three<code>Stmts</code>:<code>l1 := 1; l2 := 2; l2 := 3</code>. But an exception could only arise at the<code>Stmt</code>:<code>l2 := 2</code>. After the implementation of TrapTightener, we will get a contractible protected area which contains only the<code>Stmt</code>that might throw an exception, namely the<code>Stmt</code>:<code>l2 := 2</code>.



### EmptySwitchEliminator

EmptySwitchEliminator is a<code>BodyInterceptor</code>that removes empty switch statements which contain only the default case.

Example:

![EmptySwitchEliminator Example](./figures/EmptySwitchEliminator%20Example.png)

As shown in the example above, the switch statement in the jimple body always takes the default action. After running EmptySwitchEliminator, the switch statement is replaced with a<code>GotoStmt</code>to the default case.



### UnreachableCodeEliminator

UnreachableCodeEliminator is a<code>BodyInterceptor</code>that removes all unreachable statements.

Example:

![UnreachableCodeEliminator Example](./figures/UnreachableCodeEliminator%20Example.png)

Obviously, the code segment<code>l2 = 2; l3 = 3;</code>is unreachable. It will be removed after running the UreachableCodeEliminator.



### CopyPropagator

CopyPropagator is a<code>BodyInterceptor</code>that supports the global copy propagation and constant propagation.

Example for global copy propagation:

![UnreachableCodeEliminator Example](./figures/CopyPropagator%20Example_1.png)

Consider a code segment in the following form:

```
a = b;
...
c = use(a); // a, b, c are local variables
```

According to the copy propagation's definition, the statement<code>c = use(a)</code>can be replaced with<code>c = use(b)</code>iff both conditions are met:

* <code>a</code>is defined only one time on all the paths from<code>a = b</code>to<code>c = use(a)</code>.
* There are no definitions of<code>b</code>on any path from<code>a = b</code>to<code>c = use(a)</code>.

In the example for global copy propagation, the first used<code>l1</code>is replaced with<code>l0</code>, but the second used<code>l1</code>cannot be replaced with<code>l3</code>, because the second condition is not satisfied.

Example for constant propagation:

![CopyPropagator Example_1](figures/CopyPropagator%20Example_2.png)

Constant propagation is similar to copy propagation. Consider a code segment in the following form:

```
a = const;
...
b = use(a); // a, b are local variables, const is a constant
```

After perfoming the constant propagation, the statement<code>b = use(a)</code>can be replaced with<code>b = use(const)</code>iff<code>a</code>is not redefined on any of the paths from<code>a = const</code>to<code>b = use(a)</code>.

Therefore, the first used<code>l1</code>in the second example can be replaced with the constant<code>1</code>, but the second used<code>l1</code>cannot be replaced with the constant<code>2</code>, because<code>l1</code>is redefined on the path from<code>l1 = 2</code>to<code>l4 = use(l1)</code>. However, it can be replaced with local variable<code>l2</code>, because the both conditions of copy propagation are met.

### LocalNameStandardizer

LocalNameStandardizer is a<code>BodyInterceptor</code>that assigns a generic name to each local variable. Firstly, it will sort the local variables' order alphabetically by the string representation of their type. If there are two local variables with the same type, then the LocalNameStandardizer will use the sequence of their occurrence in jimple body to determine their order. Each assigned name consists of two parts:

* A letter to imply the local variable's type
* A digit to imply the local variable's order

The following table shows the letter corresponding to each type:

| Type of Local Variable | Letter |
| :---------------: | :---------: |
| boolean | z |
| byte | b |
| short | s |
| int | i |
| long | l |
| float | f |
| double | d |
| char | c |
| null | n |
| unknown | e |
| reference | r |


### StaticSingleAssignmentFormer

StaticSingleAssignmentFormer is a<code>BodyInterceptor</code>that transforms jimple body into SSA form, so that each local variable is assigned exactly once and defined before its first use.

Example:

![SSA Example_1](./figures/SSA%20Example_1.png)

![SSA Example_2](./figures/SSA%20Example_2.png)

In the given example, the StaticSingleAssignmentFormer assigns each<code>IdentityStmt</code>and<code>AssignStmt</code>to a new local variable . And each use uses the local variable which is most recently defined. Sometimes, it is impossible to determine the most recently defined local variable for a use in a join block. In this case, the StaticSingleAssignmentFormer will insert a<code>PhiStmt</code>in the front of the join block to merge all most recently defined local variables and assign them a new local variable.
Loading
Loading