├── .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 | *

61 | * 62 | *

This observation is implemented in the obvious way: 63 | * 64 | *

    65 | *
  1. All static fields are collected 66 | *
  2. All Thread constructor parameters are collected 67 | *
  3. The points-to sets of these values represent the base set of escapees. 68 | *
  4. All object reachable from fields of these objects are added 69 | *
  5. This process continues until a fixpoint is reached 70 | *
  6. The abstract objects in the points-to sets are converted to types 71 | *
  7. 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 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 | --------------------------------------------------------------------------------