├── .github
├── dependabot.yml
└── workflows
│ └── continuous-integration.yml
├── .gitignore
├── LICENSE.txt
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── run.py
└── src
└── main
└── java
└── com
└── ibm
└── wala
└── examples
├── analysis
├── SimpleThreadEscapeAnalysis.java
└── dataflow
│ ├── ContextInsensitiveReachingDefs.java
│ ├── ContextSensitiveReachingDefs.java
│ └── IntraprocReachingDefs.java
├── analysisscope
└── AnalysisScopeExample.java
├── drivers
├── BoundedJSCallGraphDriver.java
├── CSReachingDefsDriver.java
├── ConstructAllIRs.java
├── DemandPointsToDriver.java
├── FieldBasedJSCallGraphDriver.java
├── JSCallGraphDriver.java
├── PDFTypeHierarchy.java
├── PrintTypeHierarchy.java
├── ScopeFileCallGraph.java
└── SourceDirCallGraph.java
└── util
└── ExampleUtil.java
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gradle
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 |
--------------------------------------------------------------------------------
/.github/workflows/continuous-integration.yml:
--------------------------------------------------------------------------------
1 | name: Continuous integration
2 | on:
3 | pull_request:
4 | push:
5 | branches:
6 | - master
7 | jobs:
8 | build:
9 | name: "JDK ${{ matrix.java }} on ${{ matrix.os }}"
10 | strategy:
11 | matrix:
12 | include:
13 | - os: macos-latest
14 | java: 11
15 | - os: ubuntu-latest
16 | java: 11
17 | - os: windows-latest
18 | java: 11
19 | fail-fast: true
20 | runs-on: ${{ matrix.os }}
21 | steps:
22 | - name: Check out sources
23 | uses: actions/checkout@v2
24 | - name: 'Set up JDK ${{ matrix.java }}'
25 | uses: actions/setup-java@v1
26 | with:
27 | java-version: ${{ matrix.java }}
28 | - name: Build and test using Gradle
29 | uses: eskatos/gradle-command-action@v1
30 | with:
31 | arguments: build
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle/
2 | build/
3 | .classpath
4 | *~
5 | .project
6 | .settings/
7 | bin/
8 | .idea/
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Eclipse Public License - v 1.0
2 |
3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6 |
7 | 1. DEFINITIONS
8 |
9 | "Contribution" means:
10 |
11 | a) in the case of the initial Contributor, the initial code and documentation
12 | distributed under this Agreement, and
13 |
14 | b) in the case of each subsequent Contributor:
15 |
16 | i) changes to the Program, and
17 |
18 | ii) additions to the Program;
19 |
20 | where such changes and/or additions to the Program originate from and are
21 | distributed by that particular Contributor. A Contribution 'originates' from a
22 | Contributor if it was added to the Program by such Contributor itself or anyone
23 | acting on such Contributor's behalf. Contributions do not include additions to
24 | the Program which: (i) are separate modules of software distributed in
25 | conjunction with the Program under their own license agreement, and (ii) are not
26 | derivative works of the Program.
27 |
28 | "Contributor" means any person or entity that distributes the Program.
29 |
30 | "Licensed Patents" mean patent claims licensable by a Contributor which are
31 | necessarily infringed by the use or sale of its Contribution alone or when
32 | combined with the Program.
33 |
34 | "Program" means the Contributions distributed in accordance with this Agreement.
35 |
36 | "Recipient" means anyone who receives the Program under this Agreement,
37 | including all Contributors.
38 |
39 | 2. GRANT OF RIGHTS
40 |
41 | a) Subject to the terms of this Agreement, each Contributor hereby grants
42 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
43 | reproduce, prepare derivative works of, publicly display, publicly perform,
44 | distribute and sublicense the Contribution of such Contributor, if any, and such
45 | derivative works, in source code and object code form.
46 |
47 | b) Subject to the terms of this Agreement, each Contributor hereby grants
48 | Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed
49 | Patents to make, use, sell, offer to sell, import and otherwise transfer the
50 | Contribution of such Contributor, if any, in source code and object code
51 | form. This patent license shall apply to the combination of the Contribution and
52 | the Program if, at the time the Contribution is added by the Contributor, such
53 | addition of the Contribution causes such combination to be covered by the
54 | Licensed Patents. The patent license shall not apply to any other combinations
55 | which include the Contribution. No hardware per se is licensed hereunder.
56 |
57 | c) Recipient understands that although each Contributor grants the licenses to
58 | its Contributions set forth herein, no assurances are provided by any
59 | Contributor that the Program does not infringe the patent or other intellectual
60 | property rights of any other entity. Each Contributor disclaims any liability to
61 | Recipient for claims brought by any other entity based on infringement of
62 | intellectual property rights or otherwise. As a condition to exercising the
63 | rights and licenses granted hereunder, each Recipient hereby assumes sole
64 | responsibility to secure any other intellectual property rights needed, if
65 | any. For example, if a third party patent license is required to allow Recipient
66 | to distribute the Program, it is Recipient's responsibility to acquire that
67 | license before distributing the Program.
68 |
69 | d) Each Contributor represents that to its knowledge it has sufficient copyright
70 | rights in its Contribution, if any, to grant the copyright license set forth in
71 | this Agreement.
72 |
73 | 3. REQUIREMENTS
74 |
75 | A Contributor may choose to distribute the Program in object code form under its
76 | own license agreement, provided that:
77 |
78 | a) it complies with the terms and conditions of this Agreement; and
79 |
80 | b) its license agreement:
81 |
82 | i) effectively disclaims on behalf of all Contributors all warranties and
83 | conditions, express and implied, including warranties or conditions of title and
84 | non-infringement, and implied warranties or conditions of merchantability and
85 | fitness for a particular purpose;
86 |
87 | ii) effectively excludes on behalf of all Contributors all liability for
88 | damages, including direct, indirect, special, incidental and consequential
89 | damages, such as lost profits;
90 |
91 | iii) states that any provisions which differ from this Agreement are offered by
92 | that Contributor alone and not by any other party; and
93 |
94 | iv) states that source code for the Program is available from such Contributor,
95 | and informs licensees how to obtain it in a reasonable manner on or through a
96 | medium customarily used for software exchange.
97 |
98 | When the Program is made available in source code form:
99 |
100 | a) it must be made available under this Agreement; and
101 |
102 | b) a copy of this Agreement must be included with each copy of the Program.
103 |
104 | Contributors may not remove or alter any copyright notices contained within the
105 | Program.
106 |
107 | Each Contributor must identify itself as the originator of its Contribution, if
108 | any, in a manner that reasonably allows subsequent Recipients to identify the
109 | originator of the Contribution.
110 |
111 | 4. COMMERCIAL DISTRIBUTION
112 |
113 | Commercial distributors of software may accept certain responsibilities with
114 | respect to end users, business partners and the like. While this license is
115 | intended to facilitate the commercial use of the Program, the Contributor who
116 | includes the Program in a commercial product offering should do so in a manner
117 | which does not create potential liability for other Contributors. Therefore, if
118 | a Contributor includes the Program in a commercial product offering, such
119 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
120 | every other Contributor ("Indemnified Contributor") against any losses, damages
121 | and costs (collectively "Losses") arising from claims, lawsuits and other legal
122 | actions brought by a third party against the Indemnified Contributor to the
123 | extent caused by the acts or omissions of such Commercial Contributor in
124 | connection with its distribution of the Program in a commercial product
125 | offering. The obligations in this section do not apply to any claims or Losses
126 | relating to any actual or alleged intellectual property infringement. In order
127 | to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
128 | Contributor in writing of such claim, and b) allow the Commercial Contributor to
129 | control, and cooperate with the Commercial Contributor in, the defense and any
130 | related settlement negotiations. The Indemnified Contributor may participate in
131 | any such claim at its own expense.
132 |
133 | For example, a Contributor might include the Program in a commercial product
134 | offering, Product X. That Contributor is then a Commercial Contributor. If that
135 | Commercial Contributor then makes performance claims, or offers warranties
136 | related to Product X, those performance claims and warranties are such
137 | Commercial Contributor's responsibility alone. Under this section, the
138 | Commercial Contributor would have to defend claims against the other
139 | Contributors related to those performance claims and warranties, and if a court
140 | requires any other Contributor to pay any damages as a result, the Commercial
141 | Contributor must pay those damages.
142 |
143 | 5. NO WARRANTY
144 |
145 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
146 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
147 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
148 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
149 | Recipient is solely responsible for determining the appropriateness of using and
150 | distributing the Program and assumes all risks associated with its exercise of
151 | rights under this Agreement , including but not limited to the risks and costs
152 | of program errors, compliance with applicable laws, damage to or loss of data,
153 | programs or equipment, and unavailability or interruption of operations.
154 |
155 | 6. DISCLAIMER OF LIABILITY
156 |
157 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
158 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
159 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
160 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
161 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
162 | OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
163 | GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
164 |
165 | 7. GENERAL
166 |
167 | If any provision of this Agreement is invalid or unenforceable under applicable
168 | law, it shall not affect the validity or enforceability of the remainder of the
169 | terms of this Agreement, and without further action by the parties hereto, such
170 | provision shall be reformed to the minimum extent necessary to make such
171 | provision valid and enforceable.
172 |
173 | If Recipient institutes patent litigation against any entity (including a
174 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
175 | (excluding combinations of the Program with other software or hardware)
176 | infringes such Recipient's patent(s), then such Recipient's rights granted under
177 | Section 2(b) shall terminate as of the date such litigation is filed.
178 |
179 | All Recipient's rights under this Agreement shall terminate if it fails to
180 | comply with any of the material terms or conditions of this Agreement and does
181 | not cure such failure in a reasonable period of time after becoming aware of
182 | such noncompliance. If all Recipient's rights under this Agreement terminate,
183 | Recipient agrees to cease use and distribution of the Program as soon as
184 | reasonably practicable. However, Recipient's obligations under this Agreement
185 | and any licenses granted by Recipient relating to the Program shall continue and
186 | survive.
187 |
188 | Everyone is permitted to copy and distribute copies of this Agreement, but in
189 | order to avoid inconsistency the Agreement is copyrighted and may only be
190 | modified in the following manner. The Agreement Steward reserves the right to
191 | publish new versions (including revisions) of this Agreement from time to
192 | time. No one other than the Agreement Steward has the right to modify this
193 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse
194 | Foundation may assign the responsibility to serve as the Agreement Steward to a
195 | suitable separate entity. Each new version of the Agreement will be given a
196 | distinguishing version number. The Program (including Contributions) may always
197 | be distributed subject to the version of the Agreement under which it was
198 | received. In addition, after a new version of the Agreement is published,
199 | Contributor may elect to distribute the Program (including its Contributions)
200 | under the new version. Except as expressly stated in Sections 2(a) and 2(b)
201 | above, Recipient receives no rights or licenses to the intellectual property of
202 | any Contributor under this Agreement, whether expressly, by implication,
203 | estoppel or otherwise. All rights in the Program not expressly granted under
204 | this Agreement are reserved.
205 |
206 | This Agreement is governed by the laws of the State of New York and the
207 | intellectual property laws of the United States of America. No party to this
208 | Agreement will bring a legal action under this Agreement more than one year
209 | after the cause of action arose. Each party waives its rights to a jury trial in
210 | any resulting litigation.
211 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | WALA Starter Kit
2 | =======
3 |
4 | ### Introduction
5 |
6 | This is a small example project to help in getting started with the
7 | [WALA](https://github.com/wala/WALA) program analysis framework. You
8 | can clone and build this project to get WALA installed, and then
9 | modify it to suit your own needs.
10 |
11 | ### Requirements
12 |
13 | Requirements are a minimum JDK 11 JVM.
14 |
15 | **Note**: If you want to run the `SourceDirCallGraph` driver, you must run on Java 17 minimum, as of [WALA 1.6.4](https://github.com/wala/WALA/releases/tag/v1.6.4).
16 |
17 | ### Installation
18 |
19 | Clone the repository, and then run:
20 |
21 | ./gradlew compileJava
22 |
23 | This will pull in the WALA jars and build the sample code.
24 |
25 | ### Example analyses
26 |
27 | * [Variants of a simple dataflow analysis](https://github.com/msridhar/WALA-start/tree/master/src/main/java/com/ibm/wala/examples/analysis/dataflow), including an [example driver](https://github.com/msridhar/WALA-start/blob/master/src/main/java/com/ibm/wala/examples/drivers/CSReachingDefsDriver.java)
28 | * [Simple driver](https://github.com/msridhar/WALA-start/blob/master/src/main/java/com/ibm/wala/examples/drivers/ScopeFileCallGraph.java) for building a [call graph](http://wala.sourceforge.net/wiki/index.php/UserGuide:CallGraph) from a [scope file](http://wala.sourceforge.net/wiki/index.php/UserGuide:AnalysisScope)
29 | * [`SourceDirCallGraph` Driver](https://github.com/wala/WALA-start/blob/master/src/main/java/com/ibm/wala/examples/drivers/SourceDirCallGraph.java) for constructing a call graph from a directory of source code.
30 |
31 | See the [`drivers` folder](https://github.com/wala/WALA-start/tree/master/src/main/java/com/ibm/wala/examples/drivers) for other examples.
32 |
33 | License
34 | -------
35 |
36 | All code is available under the [Eclipse Public License](http://www.eclipse.org/legal/epl-v10.html).
37 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'application'
4 | id 'eclipse'
5 | id("com.diffplug.spotless") version "6.25.0"
6 | }
7 |
8 | java {
9 | toolchain {
10 | languageVersion = JavaLanguageVersion.of(11)
11 | }
12 | }
13 |
14 | version = '0.1'
15 | jar {
16 | manifest {
17 | attributes 'Implementation-Title': 'WALA Start',
18 | 'Implementation-Version': archiveVersion
19 | }
20 | }
21 |
22 | repositories {
23 | mavenCentral()
24 | mavenLocal()
25 | }
26 |
27 | dependencies {
28 | def walaVersion = '1.6.9'
29 |
30 | implementation "com.ibm.wala:com.ibm.wala.shrike:${walaVersion}"
31 | implementation "com.ibm.wala:com.ibm.wala.util:${walaVersion}"
32 | implementation "com.ibm.wala:com.ibm.wala.core:${walaVersion}"
33 | implementation "com.ibm.wala:com.ibm.wala.cast:${walaVersion}"
34 | implementation "com.ibm.wala:com.ibm.wala.cast.js:${walaVersion}"
35 | implementation "com.ibm.wala:com.ibm.wala.cast.js.rhino:${walaVersion}"
36 | implementation "com.ibm.wala:com.ibm.wala.cast.js:${walaVersion}"
37 | implementation "com.ibm.wala:com.ibm.wala.cast.js.rhino:${walaVersion}"
38 | implementation "com.ibm.wala:com.ibm.wala.cast.java:${walaVersion}"
39 | implementation "com.ibm.wala:com.ibm.wala.cast.java.ecj:${walaVersion}"
40 | implementation "com.ibm.wala:com.ibm.wala.dalvik:${walaVersion}"
41 | implementation "com.ibm.wala:com.ibm.wala.scandroid:${walaVersion}"
42 | testImplementation group: 'junit', name: 'junit', version: '4.+'
43 | }
44 |
45 | if (project.hasProperty('mainClass')) {
46 | mainClassName = project.getProperty('mainClass')
47 | } else {
48 | // use a default
49 | mainClassName = "com.ibm.wala.examples.drivers.PDFTypeHierarchy"
50 | }
51 |
52 | spotless {
53 | java {
54 | // apply a specific flavor of google-java-format
55 | googleJavaFormat()
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wala/WALA-start/88c406d5a936dbb14488c1591baf37bf693bb541/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 | # SPDX-License-Identifier: Apache-2.0
19 | #
20 |
21 | ##############################################################################
22 | #
23 | # Gradle start up script for POSIX generated by Gradle.
24 | #
25 | # Important for running:
26 | #
27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
28 | # noncompliant, but you have some other compliant shell such as ksh or
29 | # bash, then to run this script, type that shell name before the whole
30 | # command line, like:
31 | #
32 | # ksh Gradle
33 | #
34 | # Busybox and similar reduced shells will NOT work, because this script
35 | # requires all of these POSIX shell features:
36 | # * functions;
37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
39 | # * compound commands having a testable exit status, especially «case»;
40 | # * various built-in commands including «command», «set», and «ulimit».
41 | #
42 | # Important for patching:
43 | #
44 | # (2) This script targets any POSIX shell, so it avoids extensions provided
45 | # by Bash, Ksh, etc; in particular arrays are avoided.
46 | #
47 | # The "traditional" practice of packing multiple parameters into a
48 | # space-separated string is a well documented source of bugs and security
49 | # problems, so this is (mostly) avoided, by progressively accumulating
50 | # options in "$@", and eventually passing that to Java.
51 | #
52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
54 | # see the in-line comments for details.
55 | #
56 | # There are tweaks for specific operating systems such as AIX, CygWin,
57 | # Darwin, MinGW, and NonStop.
58 | #
59 | # (3) This script is generated from the Groovy template
60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
61 | # within the Gradle project.
62 | #
63 | # You can find Gradle at https://github.com/gradle/gradle/.
64 | #
65 | ##############################################################################
66 |
67 | # Attempt to set APP_HOME
68 |
69 | # Resolve links: $0 may be a link
70 | app_path=$0
71 |
72 | # Need this for daisy-chained symlinks.
73 | while
74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
75 | [ -h "$app_path" ]
76 | do
77 | ls=$( ls -ld "$app_path" )
78 | link=${ls#*' -> '}
79 | case $link in #(
80 | /*) app_path=$link ;; #(
81 | *) app_path=$APP_HOME$link ;;
82 | esac
83 | done
84 |
85 | # This is normally unused
86 | # shellcheck disable=SC2034
87 | APP_BASE_NAME=${0##*/}
88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
90 | ' "$PWD" ) || exit
91 |
92 | # Use the maximum available, or set MAX_FD != -1 to use that value.
93 | MAX_FD=maximum
94 |
95 | warn () {
96 | echo "$*"
97 | } >&2
98 |
99 | die () {
100 | echo
101 | echo "$*"
102 | echo
103 | exit 1
104 | } >&2
105 |
106 | # OS specific support (must be 'true' or 'false').
107 | cygwin=false
108 | msys=false
109 | darwin=false
110 | nonstop=false
111 | case "$( uname )" in #(
112 | CYGWIN* ) cygwin=true ;; #(
113 | Darwin* ) darwin=true ;; #(
114 | MSYS* | MINGW* ) msys=true ;; #(
115 | NONSTOP* ) nonstop=true ;;
116 | esac
117 |
118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
119 |
120 |
121 | # Determine the Java command to use to start the JVM.
122 | if [ -n "$JAVA_HOME" ] ; then
123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
124 | # IBM's JDK on AIX uses strange locations for the executables
125 | JAVACMD=$JAVA_HOME/jre/sh/java
126 | else
127 | JAVACMD=$JAVA_HOME/bin/java
128 | fi
129 | if [ ! -x "$JAVACMD" ] ; then
130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
131 |
132 | Please set the JAVA_HOME variable in your environment to match the
133 | location of your Java installation."
134 | fi
135 | else
136 | JAVACMD=java
137 | if ! command -v java >/dev/null 2>&1
138 | then
139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
140 |
141 | Please set the JAVA_HOME variable in your environment to match the
142 | location of your Java installation."
143 | fi
144 | fi
145 |
146 | # Increase the maximum file descriptors if we can.
147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
148 | case $MAX_FD in #(
149 | max*)
150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
151 | # shellcheck disable=SC2039,SC3045
152 | MAX_FD=$( ulimit -H -n ) ||
153 | warn "Could not query maximum file descriptor limit"
154 | esac
155 | case $MAX_FD in #(
156 | '' | soft) :;; #(
157 | *)
158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
159 | # shellcheck disable=SC2039,SC3045
160 | ulimit -n "$MAX_FD" ||
161 | warn "Could not set maximum file descriptor limit to $MAX_FD"
162 | esac
163 | fi
164 |
165 | # Collect all arguments for the java command, stacking in reverse order:
166 | # * args from the command line
167 | # * the main class name
168 | # * -classpath
169 | # * -D...appname settings
170 | # * --module-path (only if needed)
171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
172 |
173 | # For Cygwin or MSYS, switch paths to Windows format before running java
174 | if "$cygwin" || "$msys" ; then
175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
177 |
178 | JAVACMD=$( cygpath --unix "$JAVACMD" )
179 |
180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
181 | for arg do
182 | if
183 | case $arg in #(
184 | -*) false ;; # don't mess with options #(
185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
186 | [ -e "$t" ] ;; #(
187 | *) false ;;
188 | esac
189 | then
190 | arg=$( cygpath --path --ignore --mixed "$arg" )
191 | fi
192 | # Roll the args list around exactly as many times as the number of
193 | # args, so each arg winds up back in the position where it started, but
194 | # possibly modified.
195 | #
196 | # NB: a `for` loop captures its iteration list before it begins, so
197 | # changing the positional parameters here affects neither the number of
198 | # iterations, nor the values presented in `arg`.
199 | shift # remove old arg
200 | set -- "$@" "$arg" # push replacement arg
201 | done
202 | fi
203 |
204 |
205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
207 |
208 | # Collect all arguments for the java command:
209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
210 | # and any embedded shellness will be escaped.
211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
212 | # treated as '${Hostname}' itself on the command line.
213 |
214 | set -- \
215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
216 | -classpath "$CLASSPATH" \
217 | org.gradle.wrapper.GradleWrapperMain \
218 | "$@"
219 |
220 | # Stop when "xargs" is not available.
221 | if ! command -v xargs >/dev/null 2>&1
222 | then
223 | die "xargs is not available"
224 | fi
225 |
226 | # Use "xargs" to parse quoted args.
227 | #
228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
229 | #
230 | # In Bash we could simply go:
231 | #
232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
233 | # set -- "${ARGS[@]}" "$@"
234 | #
235 | # but POSIX shell has neither arrays nor command substitution, so instead we
236 | # post-process each arg (as a line of input to sed) to backslash-escape any
237 | # character that might be a shell metacharacter, then use eval to reverse
238 | # that process (while maintaining the separation between arguments), and wrap
239 | # the whole thing up as a single "set" statement.
240 | #
241 | # This will of course break if any of these variables contains a newline or
242 | # an unmatched quote.
243 | #
244 |
245 | eval "set -- $(
246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
247 | xargs -n1 |
248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
249 | tr '\n' ' '
250 | )" '"$@"'
251 |
252 | exec "$JAVACMD" "$@"
253 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import subprocess
4 | import sys
5 |
6 | java_main_class = sys.argv[1]
7 |
8 | java_app_args = ",".join(["'" + x + "'" for x in sys.argv[2:]])
9 |
10 | gradle_cmd_args = [
11 | "gradle",
12 | "run",
13 | "-PmainClass=" + java_main_class,
14 | "-PappArgs=[" + java_app_args + "]"
15 | ]
16 |
17 | print " ".join(gradle_cmd_args)
18 |
19 | subprocess.call(gradle_cmd_args)
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/analysis/SimpleThreadEscapeAnalysis.java:
--------------------------------------------------------------------------------
1 | /** Cosmin: shamelessly copy-pasted the file for testing purposes */
2 | /*******************************************************************************
3 | * Copyright (c) 2006 IBM Corporation.
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * which accompanies this distribution, and is available at
7 | * http://www.eclipse.org/legal/epl-v10.html
8 | *
9 | * Contributors:
10 | * IBM Corporation - initial API and implementation
11 | *******************************************************************************/
12 | package com.ibm.wala.examples.analysis;
13 |
14 | import com.ibm.wala.classLoader.ArrayClass;
15 | import com.ibm.wala.classLoader.IClass;
16 | import com.ibm.wala.classLoader.IField;
17 | import com.ibm.wala.classLoader.IMethod;
18 | import com.ibm.wala.classLoader.JarFileModule;
19 | import com.ibm.wala.classLoader.Language;
20 | import com.ibm.wala.client.AbstractAnalysisEngine;
21 | import com.ibm.wala.examples.util.ExampleUtil;
22 | import com.ibm.wala.ipa.callgraph.AnalysisOptions;
23 | import com.ibm.wala.ipa.callgraph.CGNode;
24 | import com.ibm.wala.ipa.callgraph.CallGraph;
25 | import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
26 | import com.ibm.wala.ipa.callgraph.Entrypoint;
27 | import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
28 | import com.ibm.wala.ipa.callgraph.impl.Util;
29 | import com.ibm.wala.ipa.callgraph.propagation.HeapModel;
30 | import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
31 | import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
32 | import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
33 | import com.ibm.wala.ipa.cha.ClassHierarchyException;
34 | import com.ibm.wala.ipa.cha.IClassHierarchy;
35 | import com.ibm.wala.properties.WalaProperties;
36 | import com.ibm.wala.types.TypeReference;
37 | import com.ibm.wala.util.CancelException;
38 | import com.ibm.wala.util.WalaException;
39 | import com.ibm.wala.util.collections.HashSetFactory;
40 | import com.ibm.wala.util.intset.OrdinalSet;
41 | import java.io.File;
42 | import java.io.IOException;
43 | import java.util.Collection;
44 | import java.util.Iterator;
45 | import java.util.Properties;
46 | import java.util.Set;
47 | import java.util.jar.JarFile;
48 |
49 | /**
50 | * A simple thread-level escape analysis: this code computes the set of classes of which some
51 | * instance may be accessed by some thread other than the one that created it.
52 | *
53 | *
The algorithm is not very bright; it is based on the observation that there are only three
54 | * ways for an object to pass from one thread to another.
55 | *
56 | *
57 | * - The object is stored into a static variable.
58 | *
- The object is stored into an instance field of a Thread
59 | *
- The object is reachable from a field of another escaping object.
60 | *
61 | *
62 | * This observation is implemented in the obvious way:
63 | *
64 | *
65 | * - All static fields are collected
66 | *
- All Thread constructor parameters are collected
67 | *
- The points-to sets of these values represent the base set of escapees.
68 | *
- All object reachable from fields of these objects are added
69 | *
- This process continues until a fixpoint is reached
70 | *
- The abstract objects in the points-to sets are converted to types
71 | *
- This set of types is returned
72 | *
73 | *
74 | * @author Julian Dolby
75 | */
76 | public class SimpleThreadEscapeAnalysis extends AbstractAnalysisEngine {
77 |
78 | private final Set applicationJarFiles;
79 |
80 | private final String applicationMainClass;
81 |
82 | /**
83 | * The two input parameters define the program to analyze: the jars of .class files and the main
84 | * class to start from.
85 | */
86 | public SimpleThreadEscapeAnalysis(Set applicationJarFiles, String applicationMainClass) {
87 | this.applicationJarFiles = applicationJarFiles;
88 | this.applicationMainClass = applicationMainClass;
89 | }
90 |
91 | @Override
92 | protected CallGraphBuilder getCallGraphBuilder(
93 | IClassHierarchy cha, AnalysisOptions options, IAnalysisCacheView cache) {
94 | return Util.makeZeroCFABuilder(Language.JAVA, options, cache, cha, scope);
95 | }
96 |
97 | /**
98 | * Given a root path, add it to the set if it is a jar, or traverse it recursively if it is a
99 | * directory.
100 | */
101 | private void collectJars(File f, Set result) throws IOException {
102 | if (f.isDirectory()) {
103 | File[] files = f.listFiles();
104 | if (files != null) {
105 | for (int i = 0; i < files.length; i++) {
106 | collectJars(files[i], result);
107 | }
108 | }
109 | } else if (f.getAbsolutePath().endsWith(".jar")) {
110 | result.add(new JarFile(f));
111 | }
112 | }
113 |
114 | /** Collect the set of JarFiles that constitute the system libraries of the running JRE. */
115 | private JarFile[] getSystemJars() throws IOException {
116 | String javaHomePath = "garbage";
117 | Set jarFiles = HashSetFactory.make();
118 |
119 | // first, see if wala.properties has been set up
120 | try {
121 | Properties p = WalaProperties.loadProperties();
122 | javaHomePath = p.getProperty(WalaProperties.J2SE_DIR);
123 | } catch (WalaException e) {
124 | // no luck.
125 | }
126 |
127 | // if not, try assuming the running JRE looks normal
128 | File x = new File(javaHomePath);
129 | if (!(x.exists() && x.isDirectory())) {
130 | javaHomePath = System.getProperty("java.home");
131 |
132 | if (!javaHomePath.endsWith(File.separator)) {
133 | javaHomePath = javaHomePath + File.separator;
134 | }
135 |
136 | javaHomePath = javaHomePath + "lib";
137 | }
138 |
139 | // find jars from chosen JRE lib path
140 | collectJars(new File(javaHomePath), jarFiles);
141 |
142 | return jarFiles.toArray(new JarFile[jarFiles.size()]);
143 | }
144 |
145 | /**
146 | * Take the given set of JarFiles that constitute the program, and return a set of Module files as
147 | * expected by the WALA machinery.
148 | */
149 | private Set getModuleFiles() {
150 | Set result = HashSetFactory.make();
151 | for (Iterator jars = applicationJarFiles.iterator(); jars.hasNext(); ) {
152 | result.add(new JarFileModule(jars.next()));
153 | }
154 |
155 | return result;
156 | }
157 |
158 | /**
159 | * The heart of the analysis.
160 | *
161 | * @throws CancelException
162 | * @throws IllegalArgumentException
163 | */
164 | public Set gatherThreadEscapingClasses()
165 | throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException {
166 |
167 | //
168 | // set the application to analyze
169 | //
170 | setModuleFiles(getModuleFiles());
171 |
172 | //
173 | // set the system jar files to use.
174 | // change this if you want to use a specific jre version
175 | //
176 | setJ2SELibraries(getSystemJars());
177 |
178 | //
179 | // the application and libraries are set, now build the scope...
180 | //
181 | buildAnalysisScope();
182 |
183 | // update exclusions
184 | ExampleUtil.addDefaultExclusions(scope);
185 |
186 | //
187 | // ...and the class hierarchy
188 | //
189 | IClassHierarchy cha = buildClassHierarchy();
190 | assert cha != null : "failed to create class hierarchy";
191 | setClassHierarchy(cha);
192 |
193 | //
194 | // entrypoints are where analysis starts
195 | //
196 | Iterable roots = Util.makeMainEntrypoints(getScope(), cha, applicationMainClass);
197 |
198 | //
199 | // analysis options controls aspects of call graph construction
200 | //
201 | AnalysisOptions options = getDefaultOptions(roots);
202 |
203 | //
204 | // build the call graph
205 | //
206 | buildCallGraph(cha, options, true, null);
207 |
208 | //
209 | // extract data for analysis
210 | //
211 | CallGraph cg = getCallGraph();
212 | PointerAnalysis pa = getPointerAnalysis();
213 |
214 | //
215 | // collect all places where objects can escape their creating thread:
216 | // 1) all static fields
217 | // 2) arguments to Thread constructors
218 | //
219 | Set escapeAnalysisRoots = HashSetFactory.make();
220 | HeapModel heapModel = pa.getHeapModel();
221 |
222 | // 1) static fields
223 | for (IClass cls : cha) {
224 | Collection staticFields = cls.getDeclaredStaticFields();
225 | for (Iterator sfs = staticFields.iterator(); sfs.hasNext(); ) {
226 | IField sf = sfs.next();
227 | if (sf.getFieldTypeReference().isReferenceType()) {
228 | escapeAnalysisRoots.add(heapModel.getPointerKeyForStaticField(sf));
229 | }
230 | }
231 | }
232 |
233 | // 2) instance fields of Threads
234 | // (we hack this by getting the 'this' parameter of all ctor calls;
235 | // this works because the next phase will add all objects transitively
236 | // reachable from fields of types in these pointer keys, and all
237 | // Thread objects must be constructed somewhere)
238 | Collection threads = cha.computeSubClasses(TypeReference.JavaLangThread);
239 | for (Iterator clss = threads.iterator(); clss.hasNext(); ) {
240 | IClass cls = clss.next();
241 | for (Iterator extends IMethod> ms = cls.getDeclaredMethods().iterator(); ms.hasNext(); ) {
242 | IMethod m = ms.next();
243 | if (m.isInit()) {
244 | Set nodes = cg.getNodes(m.getReference());
245 | for (Iterator ns = nodes.iterator(); ns.hasNext(); ) {
246 | CGNode n = ns.next();
247 | escapeAnalysisRoots.add(heapModel.getPointerKeyForLocal(n, 1));
248 | }
249 | }
250 | }
251 | }
252 |
253 | //
254 | // compute escaping types: all types flowing to escaping roots and
255 | // all types transitively reachable through their fields.
256 | //
257 | Set escapingInstanceKeys = HashSetFactory.make();
258 |
259 | //
260 | // pass 1: get abstract objects (instance keys) for escaping locations
261 | //
262 | for (Iterator rts = escapeAnalysisRoots.iterator(); rts.hasNext(); ) {
263 | PointerKey root = rts.next();
264 | OrdinalSet objects = pa.getPointsToSet(root);
265 | for (Iterator objs = objects.iterator(); objs.hasNext(); ) {
266 | InstanceKey obj = objs.next();
267 | escapingInstanceKeys.add(obj);
268 | }
269 | }
270 |
271 | //
272 | // passes 2+: get fields of escaping keys, and add pointed-to keys
273 | //
274 | Set newKeys = HashSetFactory.make();
275 | do {
276 | newKeys.clear();
277 | for (Iterator keys = escapingInstanceKeys.iterator(); keys.hasNext(); ) {
278 | InstanceKey key = keys.next();
279 | IClass type = key.getConcreteType();
280 | if (type.isReferenceType()) {
281 | if (type.isArrayClass()) {
282 | if (((ArrayClass) type).getElementClass() != null) {
283 | PointerKey fk = heapModel.getPointerKeyForArrayContents(key);
284 | OrdinalSet fobjects = pa.getPointsToSet(fk);
285 | for (Iterator fobjs = fobjects.iterator(); fobjs.hasNext(); ) {
286 | InstanceKey fobj = fobjs.next();
287 | if (!escapingInstanceKeys.contains(fobj)) {
288 | newKeys.add(fobj);
289 | }
290 | }
291 | }
292 | } else {
293 | Collection fields = type.getAllInstanceFields();
294 | for (Iterator fs = fields.iterator(); fs.hasNext(); ) {
295 | IField f = fs.next();
296 | if (f.getFieldTypeReference().isReferenceType()) {
297 | PointerKey fk = heapModel.getPointerKeyForInstanceField(key, f);
298 | OrdinalSet fobjects = pa.getPointsToSet(fk);
299 | for (Iterator fobjs = fobjects.iterator(); fobjs.hasNext(); ) {
300 | InstanceKey fobj = fobjs.next();
301 | if (!escapingInstanceKeys.contains(fobj)) {
302 | newKeys.add(fobj);
303 | }
304 | }
305 | }
306 | }
307 | }
308 | }
309 | }
310 | escapingInstanceKeys.addAll(newKeys);
311 | } while (!newKeys.isEmpty());
312 |
313 | //
314 | // get set of types from set of instance keys
315 | //
316 | Set escapingTypes = HashSetFactory.make();
317 | for (Iterator keys = escapingInstanceKeys.iterator(); keys.hasNext(); ) {
318 | InstanceKey key = keys.next();
319 | escapingTypes.add(key.getConcreteType());
320 | }
321 |
322 | return escapingTypes;
323 | }
324 |
325 | /**
326 | * This main program shows one example use of thread escape analysis: producing a set of fields to
327 | * be monitored for a dynamic race detector. The idea is that any field might have a race with two
328 | * exceptions: final fields do not have races since there are no writes to them, and volatile
329 | * fields have atomic read and write semantics provided by the VM. Hence, this piece of code
330 | * produces a list of all other fields.
331 | *
332 | * @throws CancelException
333 | * @throws IllegalArgumentException
334 | */
335 | public static void main(String[] args)
336 | throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException {
337 | String mainClassName = args[0];
338 |
339 | Set jars = HashSetFactory.make();
340 | for (int i = 1; i < args.length; i++) {
341 | jars.add(new JarFile(args[i]));
342 | }
343 |
344 | Set escapingTypes =
345 | (new SimpleThreadEscapeAnalysis(jars, mainClassName)).gatherThreadEscapingClasses();
346 |
347 | for (Iterator types = escapingTypes.iterator(); types.hasNext(); ) {
348 | IClass cls = types.next();
349 | if (!cls.isArrayClass()) {
350 | for (Iterator fs = cls.getAllFields().iterator(); fs.hasNext(); ) {
351 | IField f = fs.next();
352 | if (!f.isVolatile() && !f.isFinal()) {
353 | System.err.println(f.getReference());
354 | }
355 | }
356 | }
357 | }
358 | }
359 | }
360 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/analysis/dataflow/ContextInsensitiveReachingDefs.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2008 IBM Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | *******************************************************************************/
11 | package com.ibm.wala.examples.analysis.dataflow;
12 |
13 | import com.ibm.wala.classLoader.IField;
14 | import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
15 | import com.ibm.wala.dataflow.graph.BitVectorFramework;
16 | import com.ibm.wala.dataflow.graph.BitVectorIdentity;
17 | import com.ibm.wala.dataflow.graph.BitVectorKillAll;
18 | import com.ibm.wala.dataflow.graph.BitVectorKillGen;
19 | import com.ibm.wala.dataflow.graph.BitVectorSolver;
20 | import com.ibm.wala.dataflow.graph.BitVectorUnion;
21 | import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
22 | import com.ibm.wala.fixpoint.BitVectorVariable;
23 | import com.ibm.wala.fixpoint.UnaryOperator;
24 | import com.ibm.wala.ipa.callgraph.CGNode;
25 | import com.ibm.wala.ipa.cfg.BasicBlockInContext;
26 | import com.ibm.wala.ipa.cfg.ExplodedInterproceduralCFG;
27 | import com.ibm.wala.ipa.cha.IClassHierarchy;
28 | import com.ibm.wala.ssa.IR;
29 | import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
30 | import com.ibm.wala.ssa.SSAInstruction;
31 | import com.ibm.wala.ssa.SSAPutInstruction;
32 | import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
33 | import com.ibm.wala.util.CancelException;
34 | import com.ibm.wala.util.collections.HashMapFactory;
35 | import com.ibm.wala.util.collections.ObjectArrayMapping;
36 | import com.ibm.wala.util.collections.Pair;
37 | import com.ibm.wala.util.intset.BitVector;
38 | import com.ibm.wala.util.intset.OrdinalSetMapping;
39 | import java.util.ArrayList;
40 | import java.util.Map;
41 |
42 | /**
43 | * Computes interprocedural reaching definitions for static fields in a context-insensitive manner.
44 | */
45 | public class ContextInsensitiveReachingDefs {
46 |
47 | /** the exploded interprocedural control-flow graph on which to compute the analysis */
48 | private final ExplodedInterproceduralCFG icfg;
49 |
50 | /**
51 | * maps call graph node and instruction index of putstatic instructions to more compact numbering
52 | * for bitvectors
53 | */
54 | private final OrdinalSetMapping> putInstrNumbering;
55 |
56 | /** for resolving field references in putstatic instructions */
57 | private final IClassHierarchy cha;
58 |
59 | /**
60 | * maps each static field to the numbers of the statements (in {@link #putInstrNumbering}) that
61 | * define it; used for kills in flow functions
62 | */
63 | private final Map staticField2DefStatements = HashMapFactory.make();
64 |
65 | private static final boolean VERBOSE = true;
66 |
67 | public ContextInsensitiveReachingDefs(ExplodedInterproceduralCFG icfg, IClassHierarchy cha) {
68 | this.icfg = icfg;
69 | this.cha = cha;
70 | this.putInstrNumbering = numberPutStatics();
71 | }
72 |
73 | /** generate a numbering of the putstatic instructions */
74 | @SuppressWarnings("unchecked")
75 | private OrdinalSetMapping> numberPutStatics() {
76 | ArrayList> putInstrs = new ArrayList>();
77 | for (CGNode node : icfg.getCallGraph()) {
78 | IR ir = node.getIR();
79 | if (ir == null) {
80 | continue;
81 | }
82 | SSAInstruction[] instructions = ir.getInstructions();
83 | for (int i = 0; i < instructions.length; i++) {
84 | SSAInstruction instruction = instructions[i];
85 | if (instruction instanceof SSAPutInstruction
86 | && ((SSAPutInstruction) instruction).isStatic()) {
87 | SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
88 | // instrNum is the number that will be assigned to this putstatic
89 | int instrNum = putInstrs.size();
90 | putInstrs.add(Pair.make(node, i));
91 | // also update the mapping of static fields to def'ing statements
92 | IField field = cha.resolveField(putInstr.getDeclaredField());
93 | assert field != null;
94 | BitVector bv = staticField2DefStatements.get(field);
95 | if (bv == null) {
96 | bv = new BitVector();
97 | staticField2DefStatements.put(field, bv);
98 | }
99 | bv.set(instrNum);
100 | }
101 | }
102 | }
103 | return new ObjectArrayMapping>(
104 | putInstrs.toArray(new Pair[putInstrs.size()]));
105 | }
106 |
107 | private class TransferFunctions
108 | implements ITransferFunctionProvider<
109 | BasicBlockInContext, BitVectorVariable> {
110 |
111 | /** our meet operator is set union */
112 | @Override
113 | public AbstractMeetOperator getMeetOperator() {
114 | return BitVectorUnion.instance();
115 | }
116 |
117 | @Override
118 | public UnaryOperator getNodeTransferFunction(
119 | BasicBlockInContext node) {
120 | IExplodedBasicBlock ebb = node.getDelegate();
121 | SSAInstruction instruction = ebb.getInstruction();
122 | int instructionIndex = ebb.getFirstInstructionIndex();
123 | CGNode cgNode = node.getNode();
124 | if (instruction instanceof SSAPutInstruction
125 | && ((SSAPutInstruction) instruction).isStatic()) {
126 | // kill all defs of the same static field, and gen this instruction
127 | final SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
128 | final IField field = cha.resolveField(putInstr.getDeclaredField());
129 | assert field != null;
130 | BitVector kill = staticField2DefStatements.get(field);
131 | BitVector gen = new BitVector();
132 | gen.set(putInstrNumbering.getMappedIndex(Pair.make(cgNode, instructionIndex)));
133 | return new BitVectorKillGen(kill, gen);
134 | } else {
135 | // identity function for non-putstatic instructions
136 | return BitVectorIdentity.instance();
137 | }
138 | }
139 |
140 | /**
141 | * here we need an edge transfer function for call-to-return edges (see {@link
142 | * #getEdgeTransferFunction(BasicBlockInContext, BasicBlockInContext)})
143 | */
144 | @Override
145 | public boolean hasEdgeTransferFunctions() {
146 | return true;
147 | }
148 |
149 | @Override
150 | public boolean hasNodeTransferFunctions() {
151 | return true;
152 | }
153 |
154 | /**
155 | * for direct call-to-return edges at a call site, the edge transfer function will kill all
156 | * facts, since we only want to consider facts that arise from going through the callee
157 | */
158 | @Override
159 | public UnaryOperator getEdgeTransferFunction(
160 | BasicBlockInContext src,
161 | BasicBlockInContext dst) {
162 | if (isCallToReturnEdge(src, dst)) {
163 | return BitVectorKillAll.instance();
164 | } else {
165 | return BitVectorIdentity.instance();
166 | }
167 | }
168 |
169 | private boolean isCallToReturnEdge(
170 | BasicBlockInContext src,
171 | BasicBlockInContext dst) {
172 | SSAInstruction srcInst = src.getDelegate().getInstruction();
173 | return srcInst instanceof SSAAbstractInvokeInstruction && src.getNode().equals(dst.getNode());
174 | }
175 | }
176 |
177 | /**
178 | * run the analysis
179 | *
180 | * @return the solver used for the analysis, which contains the analysis result
181 | */
182 | public BitVectorSolver> analyze() {
183 | // the framework describes the dataflow problem, in particular the underlying graph and the
184 | // transfer functions
185 | BitVectorFramework, Pair> framework =
186 | new BitVectorFramework, Pair>(
187 | icfg, new TransferFunctions(), putInstrNumbering);
188 | BitVectorSolver> solver =
189 | new BitVectorSolver>(framework);
190 | try {
191 | solver.solve(null);
192 | } catch (CancelException e) {
193 | // this shouldn't happen
194 | assert false;
195 | }
196 | if (VERBOSE) {
197 | for (BasicBlockInContext ebb : icfg) {
198 | System.out.println(ebb);
199 | System.out.println(ebb.getDelegate().getInstruction());
200 | System.out.println(solver.getIn(ebb));
201 | System.out.println(solver.getOut(ebb));
202 | }
203 | }
204 | return solver;
205 | }
206 |
207 | /**
208 | * gets putstatic instruction corresponding to some fact number from a bitvector in the analysis
209 | * result
210 | */
211 | public Pair getNodeAndInstrForNumber(int num) {
212 | return putInstrNumbering.getMappedObject(num);
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/analysis/dataflow/ContextSensitiveReachingDefs.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2008 IBM Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | *******************************************************************************/
11 | package com.ibm.wala.examples.analysis.dataflow;
12 |
13 | import com.ibm.wala.classLoader.IField;
14 | import com.ibm.wala.dataflow.IFDS.ICFGSupergraph;
15 | import com.ibm.wala.dataflow.IFDS.IFlowFunction;
16 | import com.ibm.wala.dataflow.IFDS.IMergeFunction;
17 | import com.ibm.wala.dataflow.IFDS.IPartiallyBalancedFlowFunctions;
18 | import com.ibm.wala.dataflow.IFDS.ISupergraph;
19 | import com.ibm.wala.dataflow.IFDS.IUnaryFlowFunction;
20 | import com.ibm.wala.dataflow.IFDS.IdentityFlowFunction;
21 | import com.ibm.wala.dataflow.IFDS.KillEverything;
22 | import com.ibm.wala.dataflow.IFDS.PartiallyBalancedTabulationProblem;
23 | import com.ibm.wala.dataflow.IFDS.PartiallyBalancedTabulationSolver;
24 | import com.ibm.wala.dataflow.IFDS.PathEdge;
25 | import com.ibm.wala.dataflow.IFDS.TabulationDomain;
26 | import com.ibm.wala.dataflow.IFDS.TabulationResult;
27 | import com.ibm.wala.dataflow.IFDS.TabulationSolver;
28 | import com.ibm.wala.ipa.callgraph.AnalysisCache;
29 | import com.ibm.wala.ipa.callgraph.CGNode;
30 | import com.ibm.wala.ipa.callgraph.CallGraph;
31 | import com.ibm.wala.ipa.cfg.BasicBlockInContext;
32 | import com.ibm.wala.ipa.cha.IClassHierarchy;
33 | import com.ibm.wala.ssa.SSAInstruction;
34 | import com.ibm.wala.ssa.SSAPutInstruction;
35 | import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
36 | import com.ibm.wala.util.CancelException;
37 | import com.ibm.wala.util.collections.HashSetFactory;
38 | import com.ibm.wala.util.collections.Pair;
39 | import com.ibm.wala.util.intset.IntSet;
40 | import com.ibm.wala.util.intset.MutableMapping;
41 | import com.ibm.wala.util.intset.MutableSparseIntSet;
42 | import java.util.Collection;
43 |
44 | /**
45 | * Computes interprocedural reaching definitions for static fields in a context-sensitive manner via
46 | * {@link TabulationSolver tabulation}.
47 | */
48 | public class ContextSensitiveReachingDefs {
49 |
50 | /** used for resolving field references in putstatic instructions */
51 | private final IClassHierarchy cha;
52 |
53 | /** the supergraph over which tabulation is performed */
54 | private final ISupergraph, CGNode> supergraph;
55 |
56 | /** the tabulation domain */
57 | private final ReachingDefsDomain domain = new ReachingDefsDomain();
58 |
59 | public ContextSensitiveReachingDefs(CallGraph cg, AnalysisCache cache) {
60 | this.cha = cg.getClassHierarchy();
61 | // we use an ICFGSupergraph, which basically adapts ExplodedInterproceduralCFG to the
62 | // ISupergraph interface
63 | this.supergraph = ICFGSupergraph.make(cg);
64 | }
65 |
66 | /** controls numbering of putstatic instructions for use in tabulation */
67 | @SuppressWarnings("serial")
68 | private class ReachingDefsDomain extends MutableMapping>
69 | implements TabulationDomain, BasicBlockInContext> {
70 |
71 | @Override
72 | public boolean hasPriorityOver(
73 | PathEdge> p1,
74 | PathEdge> p2) {
75 | // don't worry about worklist priorities
76 | return false;
77 | }
78 | }
79 |
80 | private class ReachingDefsFlowFunctions
81 | implements IPartiallyBalancedFlowFunctions> {
82 |
83 | private final ReachingDefsDomain domain;
84 |
85 | protected ReachingDefsFlowFunctions(ReachingDefsDomain domain) {
86 | this.domain = domain;
87 | }
88 |
89 | /**
90 | * the flow function for flow from a callee to caller where there was no flow from caller to
91 | * callee; just the identity function
92 | *
93 | * @see ReachingDefsProblem
94 | */
95 | @Override
96 | public IFlowFunction getUnbalancedReturnFlowFunction(
97 | BasicBlockInContext src,
98 | BasicBlockInContext dest) {
99 | return IdentityFlowFunction.identity();
100 | }
101 |
102 | /** flow function from caller to callee; just the identity function */
103 | @Override
104 | public IUnaryFlowFunction getCallFlowFunction(
105 | BasicBlockInContext src,
106 | BasicBlockInContext dest,
107 | BasicBlockInContext ret) {
108 | return IdentityFlowFunction.identity();
109 | }
110 |
111 | /**
112 | * flow function from call node to return node when there are no targets for the call site; not
113 | * a case we are expecting
114 | */
115 | @Override
116 | public IUnaryFlowFunction getCallNoneToReturnFlowFunction(
117 | BasicBlockInContext src,
118 | BasicBlockInContext dest) {
119 | // if we're missing callees, just keep what information we have
120 | return IdentityFlowFunction.identity();
121 | }
122 |
123 | /**
124 | * flow function from call node to return node at a call site when callees exist. We kill
125 | * everything; surviving facts should flow out of the callee
126 | */
127 | @Override
128 | public IUnaryFlowFunction getCallToReturnFlowFunction(
129 | BasicBlockInContext src,
130 | BasicBlockInContext dest) {
131 | return KillEverything.singleton();
132 | }
133 |
134 | /** flow function for normal intraprocedural edges */
135 | @Override
136 | public IUnaryFlowFunction getNormalFlowFunction(
137 | final BasicBlockInContext src,
138 | BasicBlockInContext dest) {
139 | final IExplodedBasicBlock ebb = src.getDelegate();
140 | SSAInstruction instruction = ebb.getInstruction();
141 | if (instruction instanceof SSAPutInstruction) {
142 | final SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
143 | if (putInstr.isStatic()) {
144 | return new IUnaryFlowFunction() {
145 |
146 | @Override
147 | public IntSet getTargets(int d1) {
148 | // first, gen this statement
149 | int factNum =
150 | domain.getMappedIndex(Pair.make(src.getNode(), ebb.getFirstInstructionIndex()));
151 | assert factNum != -1;
152 | MutableSparseIntSet result = MutableSparseIntSet.makeEmpty();
153 | result.add(factNum);
154 | // if incoming statement is some different statement that defs the same static field,
155 | // kill it; otherwise, keep it
156 | if (d1 != factNum) {
157 | IField staticField = cha.resolveField(putInstr.getDeclaredField());
158 | assert staticField != null;
159 | Pair otherPutInstrAndNode = domain.getMappedObject(d1);
160 | SSAPutInstruction otherPutInstr =
161 | (SSAPutInstruction)
162 | otherPutInstrAndNode.fst.getIR()
163 | .getInstructions()[otherPutInstrAndNode.snd];
164 | IField otherStaticField = cha.resolveField(otherPutInstr.getDeclaredField());
165 | if (!staticField.equals(otherStaticField)) {
166 | result.add(d1);
167 | }
168 | }
169 | return result;
170 | }
171 |
172 | @Override
173 | public String toString() {
174 | return "Reaching Defs Normal Flow";
175 | }
176 | };
177 | }
178 | }
179 | // identity function when src block isn't for a putstatic
180 | return IdentityFlowFunction.identity();
181 | }
182 |
183 | /** standard flow function from callee to caller; just identity */
184 | @Override
185 | public IFlowFunction getReturnFlowFunction(
186 | BasicBlockInContext call,
187 | BasicBlockInContext src,
188 | BasicBlockInContext dest) {
189 | return IdentityFlowFunction.identity();
190 | }
191 | }
192 |
193 | /**
194 | * Definition of the reaching definitions tabulation problem. Note that we choose to make the
195 | * problem a partially balanced tabulation problem, where the solver is seeded with the
196 | * putstatic instructions themselves. The problem is partially balanced since a definition in a
197 | * callee used as a seed for the analysis may then reach a caller, yielding a "return" without a
198 | * corresponding "call." An alternative to this approach, used in the Reps-Horwitz-Sagiv POPL95
199 | * paper, would be to "lift" the domain of putstatic instructions with a 0 (bottom) element, have
200 | * a 0->0 transition in all transfer functions, and then seed the analysis with the path edge
201 | * (main_entry, 0) -> (main_entry, 0). We choose the partially-balanced approach to avoid
202 | * pollution of the flow functions.
203 | */
204 | private class ReachingDefsProblem
205 | implements PartiallyBalancedTabulationProblem<
206 | BasicBlockInContext, CGNode, Pair> {
207 |
208 | private ReachingDefsFlowFunctions flowFunctions = new ReachingDefsFlowFunctions(domain);
209 |
210 | /** path edges corresponding to all putstatic instructions, used as seeds for the analysis */
211 | private Collection>> initialSeeds =
212 | collectInitialSeeds();
213 |
214 | /**
215 | * we use the entry block of the CGNode as the fake entry when propagating from callee to caller
216 | * with unbalanced parens
217 | */
218 | @Override
219 | public BasicBlockInContext getFakeEntry(
220 | BasicBlockInContext node) {
221 | final CGNode cgNode = node.getNode();
222 | return getFakeEntry(cgNode);
223 | }
224 |
225 | /**
226 | * we use the entry block of the CGNode as the "fake" entry when propagating from callee to
227 | * caller with unbalanced parens
228 | */
229 | private BasicBlockInContext getFakeEntry(final CGNode cgNode) {
230 | BasicBlockInContext[] entriesForProcedure =
231 | supergraph.getEntriesForProcedure(cgNode);
232 | assert entriesForProcedure.length == 1;
233 | return entriesForProcedure[0];
234 | }
235 |
236 | /**
237 | * collect the putstatic instructions in the call graph as {@link PathEdge} seeds for the
238 | * analysis
239 | */
240 | private Collection>> collectInitialSeeds() {
241 | Collection>> result = HashSetFactory.make();
242 | for (BasicBlockInContext bb : supergraph) {
243 | IExplodedBasicBlock ebb = bb.getDelegate();
244 | SSAInstruction instruction = ebb.getInstruction();
245 | if (instruction instanceof SSAPutInstruction) {
246 | SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
247 | if (putInstr.isStatic()) {
248 | final CGNode cgNode = bb.getNode();
249 | Pair fact = Pair.make(cgNode, ebb.getFirstInstructionIndex());
250 | int factNum = domain.add(fact);
251 | BasicBlockInContext fakeEntry = getFakeEntry(cgNode);
252 | // note that the fact number used for the source of this path edge doesn't really matter
253 | result.add(PathEdge.createPathEdge(fakeEntry, factNum, bb, factNum));
254 | }
255 | }
256 | }
257 | return result;
258 | }
259 |
260 | @Override
261 | public IPartiallyBalancedFlowFunctions>
262 | getFunctionMap() {
263 | return flowFunctions;
264 | }
265 |
266 | @Override
267 | public TabulationDomain, BasicBlockInContext>
268 | getDomain() {
269 | return domain;
270 | }
271 |
272 | /** we don't need a merge function; the default unioning of tabulation works fine */
273 | @Override
274 | public IMergeFunction getMergeFunction() {
275 | return null;
276 | }
277 |
278 | @Override
279 | public ISupergraph, CGNode> getSupergraph() {
280 | return supergraph;
281 | }
282 |
283 | @Override
284 | public Collection>> initialSeeds() {
285 | return initialSeeds;
286 | }
287 | }
288 |
289 | /** perform the tabulation analysis and return the {@link TabulationResult} */
290 | public TabulationResult, CGNode, Pair>
291 | analyze() {
292 | PartiallyBalancedTabulationSolver<
293 | BasicBlockInContext, CGNode, Pair>
294 | solver =
295 | PartiallyBalancedTabulationSolver.createPartiallyBalancedTabulationSolver(
296 | new ReachingDefsProblem(), null);
297 | TabulationResult, CGNode, Pair>
298 | result = null;
299 | try {
300 | result = solver.solve();
301 | } catch (CancelException e) {
302 | // this shouldn't happen
303 | assert false;
304 | }
305 | return result;
306 | }
307 |
308 | public ISupergraph, CGNode> getSupergraph() {
309 | return supergraph;
310 | }
311 |
312 | public TabulationDomain, BasicBlockInContext>
313 | getDomain() {
314 | return domain;
315 | }
316 | }
317 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/analysis/dataflow/IntraprocReachingDefs.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2008 IBM Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | *******************************************************************************/
11 | package com.ibm.wala.examples.analysis.dataflow;
12 |
13 | import com.ibm.wala.classLoader.IField;
14 | import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
15 | import com.ibm.wala.dataflow.graph.BitVectorFramework;
16 | import com.ibm.wala.dataflow.graph.BitVectorIdentity;
17 | import com.ibm.wala.dataflow.graph.BitVectorKillGen;
18 | import com.ibm.wala.dataflow.graph.BitVectorSolver;
19 | import com.ibm.wala.dataflow.graph.BitVectorUnion;
20 | import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
21 | import com.ibm.wala.fixpoint.BitVectorVariable;
22 | import com.ibm.wala.fixpoint.UnaryOperator;
23 | import com.ibm.wala.ipa.cha.IClassHierarchy;
24 | import com.ibm.wala.ssa.IR;
25 | import com.ibm.wala.ssa.SSAInstruction;
26 | import com.ibm.wala.ssa.SSAPutInstruction;
27 | import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph;
28 | import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
29 | import com.ibm.wala.util.CancelException;
30 | import com.ibm.wala.util.collections.HashMapFactory;
31 | import com.ibm.wala.util.collections.ObjectArrayMapping;
32 | import com.ibm.wala.util.intset.BitVector;
33 | import com.ibm.wala.util.intset.OrdinalSetMapping;
34 | import java.util.ArrayList;
35 | import java.util.Map;
36 |
37 | /**
38 | * Compute intraprocedural reaching defs of global variables, i.e., the defs are {@link
39 | * SSAPutInstruction}s on static state.
40 | *
41 | * @author manu
42 | */
43 | public class IntraprocReachingDefs {
44 |
45 | /** the exploded control-flow graph on which to compute the analysis */
46 | private final ExplodedControlFlowGraph ecfg;
47 |
48 | /**
49 | * maps the index of a putstatic IR instruction to a more compact numbering for use in bitvectors
50 | */
51 | private final OrdinalSetMapping putInstrNumbering;
52 |
53 | /** used to resolve references to fields in putstatic instructions */
54 | private final IClassHierarchy cha;
55 |
56 | /**
57 | * maps each static field to the numbers of the statements (in {@link #putInstrNumbering}) that
58 | * define it; used for kills in flow functions
59 | */
60 | private final Map staticField2DefStatements = HashMapFactory.make();
61 |
62 | private static final boolean VERBOSE = true;
63 |
64 | public IntraprocReachingDefs(ExplodedControlFlowGraph ecfg, IClassHierarchy cha) {
65 | this.ecfg = ecfg;
66 | this.cha = cha;
67 | this.putInstrNumbering = numberPutStatics();
68 | }
69 |
70 | /** generate a numbering of the putstatic instructions */
71 | private OrdinalSetMapping numberPutStatics() {
72 | ArrayList putInstrs = new ArrayList();
73 | IR ir = ecfg.getIR();
74 | SSAInstruction[] instructions = ir.getInstructions();
75 | for (int i = 0; i < instructions.length; i++) {
76 | SSAInstruction instruction = instructions[i];
77 | if (instruction instanceof SSAPutInstruction
78 | && ((SSAPutInstruction) instruction).isStatic()) {
79 | SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
80 | // instrNum is the number that will be assigned to this putstatic
81 | int instrNum = putInstrs.size();
82 | putInstrs.add(i);
83 | // also update the mapping of static fields to def'ing statements
84 | IField field = cha.resolveField(putInstr.getDeclaredField());
85 | assert field != null;
86 | BitVector bv = staticField2DefStatements.get(field);
87 | if (bv == null) {
88 | bv = new BitVector();
89 | staticField2DefStatements.put(field, bv);
90 | }
91 | bv.set(instrNum);
92 | }
93 | }
94 | return new ObjectArrayMapping(putInstrs.toArray(new Integer[putInstrs.size()]));
95 | }
96 |
97 | private class TransferFunctions
98 | implements ITransferFunctionProvider {
99 |
100 | @Override
101 | public UnaryOperator getEdgeTransferFunction(
102 | IExplodedBasicBlock src, IExplodedBasicBlock dst) {
103 | throw new UnsupportedOperationException();
104 | }
105 |
106 | /** our meet operator is set union */
107 | @Override
108 | public AbstractMeetOperator getMeetOperator() {
109 | return BitVectorUnion.instance();
110 | }
111 |
112 | @Override
113 | public UnaryOperator getNodeTransferFunction(IExplodedBasicBlock node) {
114 | SSAInstruction instruction = node.getInstruction();
115 | int instructionIndex = node.getFirstInstructionIndex();
116 | if (instruction instanceof SSAPutInstruction
117 | && ((SSAPutInstruction) instruction).isStatic()) {
118 | // kill all defs of the same static field, and gen this instruction
119 | final SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
120 | final IField field = cha.resolveField(putInstr.getDeclaredField());
121 | assert field != null;
122 | BitVector kill = staticField2DefStatements.get(field);
123 | BitVector gen = new BitVector();
124 | gen.set(putInstrNumbering.getMappedIndex(instructionIndex));
125 | return new BitVectorKillGen(kill, gen);
126 | } else {
127 | // identity function for non-putstatic instructions
128 | return BitVectorIdentity.instance();
129 | }
130 | }
131 |
132 | @Override
133 | public boolean hasEdgeTransferFunctions() {
134 | // we only need transfer functions on nodes
135 | return false;
136 | }
137 |
138 | @Override
139 | public boolean hasNodeTransferFunctions() {
140 | return true;
141 | }
142 | }
143 |
144 | /**
145 | * run the analysis
146 | *
147 | * @return the solver used for the analysis, which contains the analysis result
148 | */
149 | public BitVectorSolver analyze() {
150 | // the framework describes the dataflow problem, in particular the underlying graph and the
151 | // transfer functions
152 | BitVectorFramework framework =
153 | new BitVectorFramework(
154 | ecfg, new TransferFunctions(), putInstrNumbering);
155 | BitVectorSolver solver =
156 | new BitVectorSolver(framework);
157 | try {
158 | solver.solve(null);
159 | } catch (CancelException e) {
160 | // this shouldn't happen
161 | assert false;
162 | }
163 | if (VERBOSE) {
164 | for (IExplodedBasicBlock ebb : ecfg) {
165 | System.out.println(ebb);
166 | System.out.println(ebb.getInstruction());
167 | System.out.println(solver.getIn(ebb));
168 | System.out.println(solver.getOut(ebb));
169 | }
170 | }
171 | return solver;
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/analysisscope/AnalysisScopeExample.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.analysisscope;
2 |
3 | import com.ibm.wala.core.util.config.AnalysisScopeReader;
4 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
5 | import java.io.File;
6 | import java.io.IOException;
7 |
8 | /**
9 | * This class shows two ways to create an {@link AnalysisScope}. for more information, check out
10 | * https://github.com/wala/WALA/wiki/Analysis-Scope
11 | */
12 | public class AnalysisScopeExample {
13 | /**
14 | * @param classPath paths of jars to include in analysis scope, formatted as a Java classpath
15 | * @return AnaylsisScope object created by makeJavaBinaryAnalysisScope
16 | * @throws IOException
17 | */
18 | AnalysisScope makeAnalysisScope(String classPath) throws IOException {
19 | return AnalysisScopeReader.instance.makeJavaBinaryAnalysisScope(classPath, null);
20 | }
21 |
22 | /**
23 | * @param scopeFilePath Location of a scope file in string form
24 | * @param exclusionFilePath location of an exception file
25 | * @return return an analysis scope object
26 | * @throws IOException
27 | */
28 | AnalysisScope makeAnalysisScope(String scopeFilePath, String exclusionFilePath)
29 | throws IOException {
30 | File exclusionsFile = new File(exclusionFilePath);
31 | return AnalysisScopeReader.instance.readJavaScope(
32 | scopeFilePath, exclusionsFile, AnalysisScopeExample.class.getClassLoader());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/BoundedJSCallGraphDriver.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.drivers;
2 |
3 | import com.ibm.wala.cast.js.callgraph.fieldbased.FieldBasedCallGraphBuilder;
4 | import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
5 | import com.ibm.wala.cast.js.util.CallGraph2JSON;
6 | import com.ibm.wala.cast.js.util.FieldBasedCGUtil;
7 | import com.ibm.wala.ipa.callgraph.CallGraph;
8 | import com.ibm.wala.ipa.callgraph.CallGraphStats;
9 | import com.ibm.wala.util.CancelException;
10 | import com.ibm.wala.util.NullProgressMonitor;
11 | import com.ibm.wala.util.WalaException;
12 | import java.io.IOException;
13 | import java.nio.file.Path;
14 | import java.nio.file.Paths;
15 |
16 | public class BoundedJSCallGraphDriver {
17 |
18 | /**
19 | * Driver for building indirection-bounded approximate call graphs.
20 | *
21 | * Usage: BoundedJSCallGraphDriver script_directory bound
22 | */
23 | public static void main(String[] args)
24 | throws IllegalArgumentException, IOException, CancelException, WalaException {
25 | Path scriptDir = Paths.get(args[0]);
26 | int bound = Integer.parseInt(args[1]);
27 | FieldBasedCGUtil f = new FieldBasedCGUtil(new CAstRhinoTranslatorFactory());
28 | FieldBasedCallGraphBuilder.CallGraphResult results =
29 | f.buildScriptDirBoundedCG(scriptDir, new NullProgressMonitor(), false, bound);
30 | CallGraph CG = results.getCallGraph();
31 | System.out.println(CallGraphStats.getStats(CG));
32 | System.out.println((new CallGraph2JSON()).serialize(CG));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/CSReachingDefsDriver.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.drivers;
2 |
3 | import com.ibm.wala.core.util.config.AnalysisScopeReader;
4 | import com.ibm.wala.core.util.warnings.Warnings;
5 | import com.ibm.wala.dataflow.IFDS.ISupergraph;
6 | import com.ibm.wala.dataflow.IFDS.TabulationResult;
7 | import com.ibm.wala.examples.analysis.dataflow.ContextSensitiveReachingDefs;
8 | import com.ibm.wala.examples.util.ExampleUtil;
9 | import com.ibm.wala.ipa.callgraph.AnalysisCache;
10 | import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
11 | import com.ibm.wala.ipa.callgraph.AnalysisOptions;
12 | import com.ibm.wala.ipa.callgraph.AnalysisOptions.ReflectionOptions;
13 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
14 | import com.ibm.wala.ipa.callgraph.CGNode;
15 | import com.ibm.wala.ipa.callgraph.CallGraph;
16 | import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
17 | import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException;
18 | import com.ibm.wala.ipa.callgraph.CallGraphStats;
19 | import com.ibm.wala.ipa.callgraph.Entrypoint;
20 | import com.ibm.wala.ipa.callgraph.impl.Util;
21 | import com.ibm.wala.ipa.cfg.BasicBlockInContext;
22 | import com.ibm.wala.ipa.cha.ClassHierarchyException;
23 | import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
24 | import com.ibm.wala.ipa.cha.IClassHierarchy;
25 | import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
26 | import com.ibm.wala.util.collections.Pair;
27 | import com.ibm.wala.util.io.CommandLine;
28 | import java.io.IOException;
29 | import java.util.Properties;
30 |
31 | /** Driver for running {@link ContextSensitiveReachingDefs} */
32 | public class CSReachingDefsDriver {
33 |
34 | /**
35 | * Usage: CSReachingDefsDriver -scopeFile file_path -mainClass class_name
36 | *
37 | *
Uses main() method of class_name as entrypoint.
38 | *
39 | * @throws IOException
40 | * @throws ClassHierarchyException
41 | * @throws CallGraphBuilderCancelException
42 | * @throws IllegalArgumentException
43 | */
44 | public static void main(String[] args)
45 | throws IOException,
46 | ClassHierarchyException,
47 | IllegalArgumentException,
48 | CallGraphBuilderCancelException {
49 | long start = System.currentTimeMillis();
50 | Properties p = CommandLine.parse(args);
51 | String scopeFile = p.getProperty("scopeFile");
52 | if (scopeFile == null) {
53 | throw new IllegalArgumentException("must specify scope file");
54 | }
55 | String mainClass = p.getProperty("mainClass");
56 | if (mainClass == null) {
57 | throw new IllegalArgumentException("must specify main class");
58 | }
59 | AnalysisScope scope =
60 | AnalysisScopeReader.instance.readJavaScope(
61 | scopeFile, null, CSReachingDefsDriver.class.getClassLoader());
62 | ExampleUtil.addDefaultExclusions(scope);
63 | IClassHierarchy cha = ClassHierarchyFactory.make(scope);
64 | System.out.println(cha.getNumberOfClasses() + " classes");
65 | System.out.println(Warnings.asString());
66 | Warnings.clear();
67 | AnalysisOptions options = new AnalysisOptions();
68 | Iterable entrypoints = Util.makeMainEntrypoints(cha, mainClass);
69 | options.setEntrypoints(entrypoints);
70 | // you can dial down reflection handling if you like
71 | options.setReflectionOptions(ReflectionOptions.NONE);
72 | AnalysisCache cache = new AnalysisCacheImpl();
73 | // other builders can be constructed with different Util methods
74 | CallGraphBuilder builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha);
75 | // CallGraphBuilder builder = Util.makeNCFABuilder(2, options, cache, cha, scope);
76 | // CallGraphBuilder builder = Util.makeVanillaNCFABuilder(2, options, cache, cha, scope);
77 | System.out.println("building call graph...");
78 | CallGraph cg = builder.makeCallGraph(options, null);
79 | // System.out.println(cg);
80 | long end = System.currentTimeMillis();
81 | System.out.println("done");
82 | System.out.println("took " + (end - start) + "ms");
83 | System.out.println(CallGraphStats.getStats(cg));
84 |
85 | ContextSensitiveReachingDefs reachingDefs = new ContextSensitiveReachingDefs(cg, cache);
86 | TabulationResult, CGNode, Pair>
87 | result = reachingDefs.analyze();
88 | ISupergraph, CGNode> supergraph =
89 | reachingDefs.getSupergraph();
90 |
91 | // TODO print out some analysis results
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/ConstructAllIRs.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2008 IBM Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | *******************************************************************************/
11 | package com.ibm.wala.examples.drivers;
12 |
13 | import com.ibm.wala.classLoader.IClass;
14 | import com.ibm.wala.classLoader.IMethod;
15 | import com.ibm.wala.core.util.config.AnalysisScopeReader;
16 | import com.ibm.wala.core.util.ref.ReferenceCleanser;
17 | import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
18 | import com.ibm.wala.ipa.callgraph.AnalysisOptions;
19 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
20 | import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
21 | import com.ibm.wala.ipa.callgraph.impl.Everywhere;
22 | import com.ibm.wala.ipa.cha.ClassHierarchy;
23 | import com.ibm.wala.ipa.cha.ClassHierarchyException;
24 | import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
25 | import com.ibm.wala.util.perf.Stopwatch;
26 | import java.io.IOException;
27 |
28 | /**
29 | * An analysis skeleton that simply constructs IRs for all methods in a class hierarchy. Illustrates
30 | * the use of {@link ReferenceCleanser} to improve running time / reduce memory usage.
31 | */
32 | public class ConstructAllIRs {
33 |
34 | /** Should we periodically clear out soft reference caches in an attempt to help the GC? */
35 | private static final boolean PERIODIC_WIPE_SOFT_CACHES = true;
36 |
37 | /** Interval which defines the period to clear soft reference caches */
38 | private static final int WIPE_SOFT_CACHE_INTERVAL = 2500;
39 |
40 | /** Counter for wiping soft caches */
41 | private static int wipeCount = 0;
42 |
43 | /**
44 | * First command-line argument should be location of scope file for application to analyze
45 | *
46 | * @throws IOException
47 | * @throws ClassHierarchyException
48 | */
49 | public static void main(String[] args) throws IOException, ClassHierarchyException {
50 | String scopeFile = args[0];
51 |
52 | // measure running time
53 | Stopwatch s = new Stopwatch();
54 | s.start();
55 | AnalysisScope scope =
56 | AnalysisScopeReader.instance.readJavaScope(
57 | scopeFile, null, ConstructAllIRs.class.getClassLoader());
58 |
59 | // build a type hierarchy
60 | System.out.print("building class hierarchy...");
61 | ClassHierarchy cha = ClassHierarchyFactory.make(scope);
62 | System.out.println("done");
63 |
64 | // register class hierarchy and AnalysisCache with the reference cleanser, so that their soft
65 | // references are appropriately wiped
66 | ReferenceCleanser.registerClassHierarchy(cha);
67 | AnalysisOptions options = new AnalysisOptions();
68 | IAnalysisCacheView cache = new AnalysisCacheImpl(options.getSSAOptions());
69 | ReferenceCleanser.registerCache(cache);
70 |
71 | System.out.print("building IRs...");
72 | for (IClass klass : cha) {
73 | for (IMethod method : klass.getDeclaredMethods()) {
74 | wipeSoftCaches();
75 | // construct an IR; it will be cached
76 | cache.getIR(method, Everywhere.EVERYWHERE);
77 | }
78 | }
79 | System.out.println("done");
80 | s.stop();
81 | System.out.println("RUNNING TIME: " + s.getElapsedMillis());
82 | }
83 |
84 | private static void wipeSoftCaches() {
85 | if (PERIODIC_WIPE_SOFT_CACHES) {
86 | wipeCount++;
87 | if (wipeCount >= WIPE_SOFT_CACHE_INTERVAL) {
88 | wipeCount = 0;
89 | ReferenceCleanser.clearSoftCaches();
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/DemandPointsToDriver.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.drivers;
2 |
3 | import com.ibm.wala.classLoader.CallSiteReference;
4 | import com.ibm.wala.classLoader.Language;
5 | import com.ibm.wala.core.util.config.AnalysisScopeReader;
6 | import com.ibm.wala.demandpa.alg.DemandRefinementPointsTo;
7 | import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineCGPolicy;
8 | import com.ibm.wala.demandpa.alg.refinepolicy.NeverRefineFieldsPolicy;
9 | import com.ibm.wala.demandpa.alg.refinepolicy.RefinementPolicyFactory;
10 | import com.ibm.wala.demandpa.alg.refinepolicy.SinglePassRefinementPolicy;
11 | import com.ibm.wala.demandpa.alg.statemachine.DummyStateMachine;
12 | import com.ibm.wala.demandpa.alg.statemachine.StateMachineFactory;
13 | import com.ibm.wala.demandpa.flowgraph.IFlowLabel;
14 | import com.ibm.wala.demandpa.util.MemoryAccessMap;
15 | import com.ibm.wala.demandpa.util.SimpleMemoryAccessMap;
16 | import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
17 | import com.ibm.wala.ipa.callgraph.AnalysisOptions;
18 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
19 | import com.ibm.wala.ipa.callgraph.CGNode;
20 | import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
21 | import com.ibm.wala.ipa.callgraph.cha.CHACallGraph;
22 | import com.ibm.wala.ipa.callgraph.impl.Util;
23 | import com.ibm.wala.ipa.callgraph.propagation.HeapModel;
24 | import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
25 | import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
26 | import com.ibm.wala.ipa.cha.ClassHierarchy;
27 | import com.ibm.wala.ipa.cha.ClassHierarchyException;
28 | import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
29 | import com.ibm.wala.ssa.IR;
30 | import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
31 | import com.ibm.wala.types.ClassLoaderReference;
32 | import com.ibm.wala.util.CancelException;
33 | import com.ibm.wala.util.collections.Pair;
34 | import java.io.IOException;
35 | import java.util.Collection;
36 | import java.util.Iterator;
37 |
38 | /**
39 | * Example driver for using the demand-driven points-to analysis, {@link DemandRefinementPointsTo}
40 | */
41 | public class DemandPointsToDriver {
42 |
43 | /**
44 | * Shows how to run the demand-driven points-to analysis. First and only command-line argument is
45 | * the classpath
46 | */
47 | public static void main(String[] args)
48 | throws IOException, ClassHierarchyException, CancelException {
49 | // Construct the AnalysisScope from the class path.
50 | String classpath = args[0];
51 | AnalysisScope scope = AnalysisScopeReader.instance.makeJavaBinaryAnalysisScope(classpath, null);
52 | // We need a baseline call graph. Here we use a CHACallGraph based on a ClassHierarchy.
53 | ClassHierarchy cha = ClassHierarchyFactory.make(scope);
54 | CHACallGraph chaCG = new CHACallGraph(cha);
55 | chaCG.init(Util.makeMainEntrypoints(cha));
56 | AnalysisOptions options = new AnalysisOptions();
57 | IAnalysisCacheView cache = new AnalysisCacheImpl();
58 | // We also need a heap model to create InstanceKeys for allocation sites, etc.
59 | // Here we use a 0-1 CFA builder, which will give a heap abstraction similar to
60 | // context-insensitive Andersen's analysis
61 | HeapModel heapModel = Util.makeZeroOneCFABuilder(Language.JAVA, options, cache, cha);
62 | // The MemoryAccessMap helps the demand analysis find matching field reads and writes
63 | MemoryAccessMap mam = new SimpleMemoryAccessMap(chaCG, heapModel, false);
64 | // The StateMachineFactory helps in tracking additional states like calling contexts.
65 | // For context-insensitive analysis we use a DummyStateMachine.Factory
66 | StateMachineFactory stateMachineFactory = new DummyStateMachine.Factory<>();
67 | DemandRefinementPointsTo drpt =
68 | DemandRefinementPointsTo.makeWithDefaultFlowGraph(
69 | chaCG, heapModel, mam, cha, options, stateMachineFactory);
70 | // The RefinementPolicyFactory determines how the analysis refines match edges (see PLDI'06
71 | // paper). Here we use a policy that does not perform refinement and just uses a fixed budget
72 | // for a single pass
73 | RefinementPolicyFactory refinementPolicyFactory =
74 | new SinglePassRefinementPolicy.Factory(
75 | new NeverRefineFieldsPolicy(), new NeverRefineCGPolicy(), 1000);
76 | drpt.setRefinementPolicyFactory(refinementPolicyFactory);
77 | // We need some variables to query. Here, we find calls to a method named "elementAt" inside
78 | // application code, and query the receiver at such calls. Customize for your own needs.
79 | for (CGNode node : chaCG) {
80 | if (!node.getMethod()
81 | .getDeclaringClass()
82 | .getClassLoader()
83 | .getReference()
84 | .equals(ClassLoaderReference.Application)) {
85 | continue;
86 | }
87 | IR ir = node.getIR();
88 | if (ir == null) continue;
89 | Iterator callSites = ir.iterateCallSites();
90 | while (callSites.hasNext()) {
91 | CallSiteReference site = callSites.next();
92 | if (site.getDeclaredTarget().getName().toString().equals("elementAt")) {
93 | System.out.println(site + " in " + node);
94 | SSAAbstractInvokeInstruction[] calls = ir.getCalls(site);
95 | PointerKey pk = heapModel.getPointerKeyForLocal(node, calls[0].getUse(0));
96 | Pair> pointsTo =
97 | drpt.getPointsTo(pk, k -> true);
98 | System.out.println("POINTS TO RESULT: " + pointsTo);
99 | }
100 | }
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/FieldBasedJSCallGraphDriver.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.drivers;
2 |
3 | import com.ibm.wala.cast.js.callgraph.fieldbased.FieldBasedCallGraphBuilder;
4 | import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
5 | import com.ibm.wala.cast.js.util.CallGraph2JSON;
6 | import com.ibm.wala.cast.js.util.FieldBasedCGUtil;
7 | import com.ibm.wala.ipa.callgraph.CallGraph;
8 | import com.ibm.wala.ipa.callgraph.CallGraphStats;
9 | import com.ibm.wala.util.CancelException;
10 | import com.ibm.wala.util.WalaException;
11 | import java.io.IOException;
12 | import java.net.URL;
13 | import java.nio.file.Path;
14 | import java.nio.file.Paths;
15 |
16 | public class FieldBasedJSCallGraphDriver {
17 |
18 | /**
19 | * Usage: JSCallGraphDriver path_to_js_file
20 | *
21 | * @param args
22 | * @throws WalaException
23 | * @throws CancelException
24 | * @throws IOException
25 | * @throws IllegalArgumentException
26 | */
27 | public static void main(String[] args)
28 | throws IllegalArgumentException, IOException, CancelException, WalaException {
29 | Path path = Paths.get(args[0]);
30 | FieldBasedCGUtil f = new FieldBasedCGUtil(new CAstRhinoTranslatorFactory());
31 | URL url = path.toUri().toURL();
32 | FieldBasedCallGraphBuilder.CallGraphResult results =
33 | f.buildScriptCG(url, FieldBasedCGUtil.BuilderType.OPTIMISTIC_WORKLIST, null, false);
34 | CallGraph CG = results.getCallGraph();
35 | System.out.println(CallGraphStats.getStats(CG));
36 | System.out.println((new CallGraph2JSON()).serialize(CG));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/JSCallGraphDriver.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.drivers;
2 |
3 | import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil;
4 | import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
5 | import com.ibm.wala.cast.js.util.JSCallGraphBuilderUtil;
6 | import com.ibm.wala.ipa.callgraph.CallGraph;
7 | import com.ibm.wala.ipa.callgraph.CallGraphStats;
8 | import com.ibm.wala.util.CancelException;
9 | import com.ibm.wala.util.WalaException;
10 | import java.io.IOException;
11 | import java.nio.file.Path;
12 | import java.nio.file.Paths;
13 |
14 | public class JSCallGraphDriver {
15 |
16 | /**
17 | * Usage: JSCallGraphDriver path_to_js_file
18 | *
19 | * @param args
20 | * @throws WalaException
21 | * @throws CancelException
22 | * @throws IOException
23 | * @throws IllegalArgumentException
24 | */
25 | public static void main(String[] args)
26 | throws IllegalArgumentException, IOException, CancelException, WalaException {
27 | Path path = Paths.get(args[0]);
28 | JSCallGraphUtil.setTranslatorFactory(new CAstRhinoTranslatorFactory());
29 | CallGraph CG =
30 | JSCallGraphBuilderUtil.makeScriptCG(
31 | path.getParent().toString(), path.getFileName().toString());
32 | System.out.println(CallGraphStats.getStats(CG));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/PDFTypeHierarchy.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2002 - 2006 IBM Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | *******************************************************************************/
11 | package com.ibm.wala.examples.drivers;
12 |
13 | import com.ibm.wala.classLoader.IClass;
14 | import com.ibm.wala.core.util.config.AnalysisScopeReader;
15 | import com.ibm.wala.core.viz.PDFViewUtil;
16 | import com.ibm.wala.examples.util.ExampleUtil;
17 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
18 | import com.ibm.wala.ipa.cha.ClassHierarchy;
19 | import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
20 | import com.ibm.wala.ipa.cha.IClassHierarchy;
21 | import com.ibm.wala.types.ClassLoaderReference;
22 | import com.ibm.wala.util.WalaException;
23 | import com.ibm.wala.util.collections.CollectionFilter;
24 | import com.ibm.wala.util.graph.Graph;
25 | import com.ibm.wala.util.graph.GraphSlicer;
26 | import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph;
27 | import com.ibm.wala.util.viz.DotUtil;
28 | import java.io.File;
29 | import java.io.IOException;
30 | import java.util.Collection;
31 | import java.util.function.Predicate;
32 |
33 | /**
34 | * This simple example WALA application builds a TypeHierarchy and fires off ghostview to viz a DOT
35 | * representation.
36 | *
37 | * @author sfink
38 | */
39 | public class PDFTypeHierarchy {
40 | // This example takes one command-line argument, so args[1] should be the "-classpath" parameter
41 | static final int CLASSPATH_INDEX = 1;
42 |
43 | public static void main(String[] args) throws IOException {
44 | run(args);
45 | }
46 |
47 | public static Process run(String[] args) throws IOException {
48 | try {
49 | validateCommandLine(args);
50 | String classpath = args[CLASSPATH_INDEX];
51 | AnalysisScope scope =
52 | AnalysisScopeReader.instance.makeJavaBinaryAnalysisScope(classpath, null);
53 | ExampleUtil.addDefaultExclusions(scope);
54 |
55 | // invoke WALA to build a class hierarchy
56 | ClassHierarchy cha = ClassHierarchyFactory.make(scope);
57 |
58 | Graph g = typeHierarchy2Graph(cha);
59 |
60 | g = pruneForAppLoader(g);
61 | String dotFile = File.createTempFile("out", ".dt").getAbsolutePath();
62 | String pdfFile = File.createTempFile("out", ".pdf").getAbsolutePath();
63 | String dotExe = "dot";
64 | String gvExe = "open";
65 | DotUtil.dotify(g, null, dotFile, pdfFile, dotExe);
66 | return PDFViewUtil.launchPDFView(pdfFile, gvExe);
67 |
68 | } catch (WalaException e) {
69 | // TODO Auto-generated catch block
70 | e.printStackTrace();
71 | return null;
72 | }
73 | }
74 |
75 | public static Graph pruneGraph(Graph g, Predicate f) {
76 | Collection slice = GraphSlicer.slice(g, f);
77 | return GraphSlicer.prune(g, new CollectionFilter<>(slice));
78 | }
79 |
80 | /** Restrict g to nodes from the Application loader */
81 | public static Graph pruneForAppLoader(Graph g) throws WalaException {
82 | Predicate f =
83 | c -> (c.getClassLoader().getReference().equals(ClassLoaderReference.Application));
84 | return pruneGraph(g, f);
85 | }
86 |
87 | /**
88 | * Validate that the command-line arguments obey the expected usage.
89 | *
90 | * Usage: args[0] : "-classpath" args[1] : String, a ";"-delimited class path
91 | *
92 | * @throws UnsupportedOperationException if command-line is malformed.
93 | */
94 | public static void validateCommandLine(String[] args) {
95 | if (args.length < 2) {
96 | throw new UnsupportedOperationException("must have at least 2 command-line arguments");
97 | }
98 | if (!args[0].equals("-classpath")) {
99 | throw new UnsupportedOperationException(
100 | "invalid command-line, args[0] should be -classpath, but is " + args[0]);
101 | }
102 | }
103 |
104 | /**
105 | * Return a view of an {@link IClassHierarchy} as a {@link Graph}, with edges from classes to
106 | * immediate subtypes
107 | */
108 | public static Graph typeHierarchy2Graph(IClassHierarchy cha) throws WalaException {
109 | Graph result = SlowSparseNumberedGraph.make();
110 | for (IClass c : cha) {
111 | result.addNode(c);
112 | }
113 | for (IClass c : cha) {
114 | for (IClass x : cha.getImmediateSubclasses(c)) {
115 | result.addEdge(c, x);
116 | }
117 | if (c.isInterface()) {
118 | for (IClass x : cha.getImplementors(c.getReference())) {
119 | result.addEdge(c, x);
120 | }
121 | }
122 | }
123 | return result;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/PrintTypeHierarchy.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2002 - 2006 IBM Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | *******************************************************************************/
11 | package com.ibm.wala.examples.drivers;
12 |
13 | import com.ibm.wala.core.util.config.AnalysisScopeReader;
14 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
15 | import com.ibm.wala.ipa.cha.ClassHierarchy;
16 | import com.ibm.wala.ipa.cha.ClassHierarchyException;
17 | import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
18 | import java.io.IOException;
19 |
20 | /** Simple WALA driver to build and print out a {@link ClassHierarchy}. */
21 | public class PrintTypeHierarchy {
22 |
23 | public static void main(String[] args) throws IOException, ClassHierarchyException {
24 | String classpath = args[0];
25 | AnalysisScope scope = AnalysisScopeReader.instance.makeJavaBinaryAnalysisScope(classpath, null);
26 | ClassHierarchy cha = ClassHierarchyFactory.make(scope);
27 | System.out.println(cha);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/ScopeFileCallGraph.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2008 IBM Corporation.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/epl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | *******************************************************************************/
11 | package com.ibm.wala.examples.drivers;
12 |
13 | import com.ibm.wala.classLoader.IClass;
14 | import com.ibm.wala.classLoader.IMethod;
15 | import com.ibm.wala.core.util.config.AnalysisScopeReader;
16 | import com.ibm.wala.core.util.strings.StringStuff;
17 | import com.ibm.wala.core.util.warnings.Warnings;
18 | import com.ibm.wala.examples.util.ExampleUtil;
19 | import com.ibm.wala.ipa.callgraph.AnalysisCache;
20 | import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
21 | import com.ibm.wala.ipa.callgraph.AnalysisOptions;
22 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
23 | import com.ibm.wala.ipa.callgraph.CallGraph;
24 | import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
25 | import com.ibm.wala.ipa.callgraph.CallGraphStats;
26 | import com.ibm.wala.ipa.callgraph.Entrypoint;
27 | import com.ibm.wala.ipa.callgraph.impl.DefaultEntrypoint;
28 | import com.ibm.wala.ipa.callgraph.impl.Util;
29 | import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
30 | import com.ibm.wala.ipa.cha.ClassHierarchyException;
31 | import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
32 | import com.ibm.wala.ipa.cha.IClassHierarchy;
33 | import com.ibm.wala.types.ClassLoaderReference;
34 | import com.ibm.wala.types.TypeReference;
35 | import com.ibm.wala.util.CancelException;
36 | import com.ibm.wala.util.io.CommandLine;
37 | import java.io.IOException;
38 | import java.util.ArrayList;
39 | import java.util.Collection;
40 | import java.util.Properties;
41 |
42 | /**
43 | * Driver that constructs a call graph for an application specified via a scope file. Useful for
44 | * getting some code to copy-paste.
45 | */
46 | public class ScopeFileCallGraph {
47 |
48 | /**
49 | * Usage: ScopeFileCallGraph -scopeFile file_path [-entryClass class_name | -mainClass class_name]
50 | *
51 | * If given -mainClass, uses main() method of class_name as entrypoint. If given -entryClass,
52 | * uses all public methods of class_name.
53 | *
54 | * @throws IOException
55 | * @throws ClassHierarchyException
56 | * @throws CancelException
57 | * @throws IllegalArgumentException
58 | */
59 | public static void main(String[] args)
60 | throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException {
61 | long start = System.currentTimeMillis();
62 | Properties p = CommandLine.parse(args);
63 | String scopeFile = p.getProperty("scopeFile");
64 | String entryClass = p.getProperty("entryClass");
65 | String mainClass = p.getProperty("mainClass");
66 | if (mainClass != null && entryClass != null) {
67 | throw new IllegalArgumentException("only specify one of mainClass or entryClass");
68 | }
69 | AnalysisScope scope =
70 | AnalysisScopeReader.instance.readJavaScope(
71 | scopeFile, null, ScopeFileCallGraph.class.getClassLoader());
72 | // set exclusions. we use these exclusions as standard for handling JDK 8
73 | ExampleUtil.addDefaultExclusions(scope);
74 | IClassHierarchy cha = ClassHierarchyFactory.make(scope);
75 | System.out.println(cha.getNumberOfClasses() + " classes");
76 | System.out.println(Warnings.asString());
77 | Warnings.clear();
78 | AnalysisOptions options = new AnalysisOptions();
79 | Iterable entrypoints =
80 | entryClass != null
81 | ? makePublicEntrypoints(cha, entryClass)
82 | : Util.makeMainEntrypoints(cha, mainClass);
83 | options.setEntrypoints(entrypoints);
84 | // For a CHA call graph
85 | // CHACallGraph CG = new CHACallGraph(cha);
86 | // CG.init(entrypoints);
87 | // For other call graphs
88 | // you can dial down reflection handling if you like
89 | // options.setReflectionOptions(ReflectionOptions.NONE);
90 | AnalysisCache cache = new AnalysisCacheImpl();
91 | // other builders can be constructed with different Util methods
92 | CallGraphBuilder builder =
93 | Util.makeZeroOneContainerCFABuilder(options, cache, cha);
94 | // CallGraphBuilder builder = Util.makeZeroCFABuilder(Language.JAVA, options,
95 | // cache, cha);
96 | // CallGraphBuilder builder = Util.makeNCFABuilder(2, options, cache, cha, scope);
97 | // CallGraphBuilder builder = Util.makeVanillaNCFABuilder(2, options, cache, cha, scope);
98 | // CallGraphBuilder builder = Util.makeVanillaNCFABuilder(2, options, cache, cha, scope);
99 | System.out.println("building call graph...");
100 | CallGraph cg = builder.makeCallGraph(options, null);
101 |
102 | long end = System.currentTimeMillis();
103 | System.out.println("done");
104 | System.out.println("took " + (end - start) + "ms");
105 | System.out.println(CallGraphStats.getStats(cg));
106 | }
107 |
108 | private static Iterable makePublicEntrypoints(
109 | IClassHierarchy cha, String entryClass) {
110 | Collection result = new ArrayList<>();
111 | IClass klass =
112 | cha.lookupClass(
113 | TypeReference.findOrCreate(
114 | ClassLoaderReference.Application,
115 | StringStuff.deployment2CanonicalTypeString(entryClass)));
116 | for (IMethod m : klass.getDeclaredMethods()) {
117 | if (m.isPublic()) {
118 | result.add(new DefaultEntrypoint(m, cha));
119 | }
120 | }
121 | return result;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/drivers/SourceDirCallGraph.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.drivers;
2 |
3 | import com.ibm.wala.cast.ir.ssa.AstIRFactory;
4 | import com.ibm.wala.cast.java.client.impl.ZeroOneContainerCFABuilderFactory;
5 | import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope;
6 | import com.ibm.wala.cast.java.translator.jdt.ecj.ECJClassLoaderFactory;
7 | import com.ibm.wala.classLoader.ClassLoaderFactory;
8 | import com.ibm.wala.classLoader.SourceDirectoryTreeModule;
9 | import com.ibm.wala.classLoader.SourceFileModule;
10 | import com.ibm.wala.core.util.warnings.Warnings;
11 | import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
12 | import com.ibm.wala.ipa.callgraph.AnalysisOptions;
13 | import com.ibm.wala.ipa.callgraph.AnalysisOptions.ReflectionOptions;
14 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
15 | import com.ibm.wala.ipa.callgraph.CallGraph;
16 | import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
17 | import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException;
18 | import com.ibm.wala.ipa.callgraph.CallGraphStats;
19 | import com.ibm.wala.ipa.callgraph.Entrypoint;
20 | import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
21 | import com.ibm.wala.ipa.callgraph.impl.Util;
22 | import com.ibm.wala.ipa.cha.ClassHierarchyException;
23 | import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
24 | import com.ibm.wala.ipa.cha.IClassHierarchy;
25 | import com.ibm.wala.properties.WalaProperties;
26 | import com.ibm.wala.ssa.SymbolTable;
27 | import com.ibm.wala.types.ClassLoaderReference;
28 | import com.ibm.wala.util.io.CommandLine;
29 | import java.io.File;
30 | import java.io.IOException;
31 | import java.util.Arrays;
32 | import java.util.Properties;
33 | import java.util.jar.JarFile;
34 |
35 | /**
36 | * Driver that constructs a call graph for an application specified as a directory of source code.
37 | * Example of using the JDT front-end based on ECJ. Useful for getting some code to copy-paste.
38 | */
39 | public class SourceDirCallGraph {
40 |
41 | @FunctionalInterface
42 | public interface Processor {
43 | public void process(CallGraph CG, CallGraphBuilder> builder, long time);
44 | }
45 |
46 | /**
47 | * Usage: SourceDirCallGraph -sourceDir file_path -mainClass class_name
48 | *
49 | * If given -mainClass, uses main() method of class_name as entrypoint. Class name should start
50 | * with an 'L'.
51 | *
52 | *
Example args: -sourceDir /tmp/srcTest -mainClass LFoo
53 | */
54 | public static void main(String[] args)
55 | throws ClassHierarchyException,
56 | IllegalArgumentException,
57 | CallGraphBuilderCancelException,
58 | IOException {
59 | System.out.println(Arrays.toString(args));
60 | new SourceDirCallGraph()
61 | .doit(
62 | args,
63 | (cg, builder, time) -> {
64 | System.out.println("done");
65 | System.out.println("took " + time + "ms");
66 | System.out.println(CallGraphStats.getStats(cg));
67 | });
68 | }
69 |
70 | protected ClassLoaderFactory getLoaderFactory(AnalysisScope scope) {
71 | return new ECJClassLoaderFactory(scope.getExclusions());
72 | }
73 |
74 | public void doit(String[] args, Processor processor)
75 | throws ClassHierarchyException,
76 | IllegalArgumentException,
77 | CallGraphBuilderCancelException,
78 | IOException {
79 | long start = System.currentTimeMillis();
80 | Properties p = CommandLine.parse(args);
81 | String sourceDir = p.getProperty("sourceDir");
82 | String mainClass = p.getProperty("mainClass");
83 | AnalysisScope scope = new JavaSourceAnalysisScope();
84 | // add standard libraries to scope
85 | String[] stdlibs = WalaProperties.getJ2SEJarFiles();
86 | for (String stdlib : stdlibs) {
87 | scope.addToScope(ClassLoaderReference.Primordial, new JarFile(stdlib));
88 | }
89 | // add the source directory
90 | File root = new File(sourceDir);
91 | if (root.isDirectory()) {
92 | scope.addToScope(JavaSourceAnalysisScope.SOURCE, new SourceDirectoryTreeModule(root));
93 | } else {
94 | String srcFileName = sourceDir.substring(sourceDir.lastIndexOf(File.separator) + 1);
95 | assert root.exists() : "couldn't find " + sourceDir;
96 | scope.addToScope(
97 | JavaSourceAnalysisScope.SOURCE, new SourceFileModule(root, srcFileName, null));
98 | }
99 |
100 | // build the class hierarchy
101 | IClassHierarchy cha = ClassHierarchyFactory.make(scope, getLoaderFactory(scope));
102 | System.out.println(cha.getNumberOfClasses() + " classes");
103 | System.out.println(Warnings.asString());
104 | Warnings.clear();
105 | AnalysisOptions options = new AnalysisOptions();
106 | Iterable entrypoints = getEntrypoints(mainClass, cha);
107 | options.setEntrypoints(entrypoints);
108 | options.getSSAOptions().setDefaultValues(SymbolTable::getDefaultValue);
109 | // you can dial down reflection handling if you like
110 | options.setReflectionOptions(ReflectionOptions.NONE);
111 | IAnalysisCacheView cache =
112 | new AnalysisCacheImpl(AstIRFactory.makeDefaultFactory(), options.getSSAOptions());
113 | // CallGraphBuilder builder = new ZeroCFABuilderFactory().make(options, cache,
114 | // cha, scope,
115 | // false);
116 | CallGraphBuilder> builder = new ZeroOneContainerCFABuilderFactory().make(options, cache, cha);
117 | System.out.println("building call graph...");
118 | CallGraph cg = builder.makeCallGraph(options, null);
119 | long end = System.currentTimeMillis();
120 |
121 | processor.process(cg, builder, end - start);
122 | }
123 |
124 | protected Iterable getEntrypoints(String mainClass, IClassHierarchy cha) {
125 | return Util.makeMainEntrypoints(JavaSourceAnalysisScope.SOURCE, cha, new String[] {mainClass});
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/main/java/com/ibm/wala/examples/util/ExampleUtil.java:
--------------------------------------------------------------------------------
1 | package com.ibm.wala.examples.util;
2 |
3 | import com.ibm.wala.ipa.callgraph.AnalysisScope;
4 | import com.ibm.wala.util.config.FileOfClasses;
5 | import java.io.ByteArrayInputStream;
6 | import java.io.IOException;
7 | import java.io.UnsupportedEncodingException;
8 |
9 | public class ExampleUtil {
10 |
11 | // more aggressive exclusions to avoid library blowup
12 | // in interprocedural tests
13 | private static final String EXCLUSIONS =
14 | "java\\/awt\\/.*\n"
15 | + "javax\\/swing\\/.*\n"
16 | + "sun\\/awt\\/.*\n"
17 | + "sun\\/swing\\/.*\n"
18 | + "com\\/sun\\/.*\n"
19 | + "sun\\/.*\n"
20 | + "org\\/netbeans\\/.*\n"
21 | + "org\\/openide\\/.*\n"
22 | + "com\\/ibm\\/crypto\\/.*\n"
23 | + "com\\/ibm\\/security\\/.*\n"
24 | + "org\\/apache\\/xerces\\/.*\n"
25 | + "java\\/security\\/.*\n"
26 | + "";
27 |
28 | public static void addDefaultExclusions(AnalysisScope scope)
29 | throws UnsupportedEncodingException, IOException {
30 | scope.setExclusions(
31 | new FileOfClasses(new ByteArrayInputStream(ExampleUtil.EXCLUSIONS.getBytes("UTF-8"))));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------