diff --git a/jalangi2/.github/workflows/continuous-integration.yml b/jalangi2/.github/workflows/continuous-integration.yml
new file mode 100644
index 00000000000..eb70259288b
--- /dev/null
+++ b/jalangi2/.github/workflows/continuous-integration.yml
@@ -0,0 +1,19 @@
+name: Continuous integration
+
+on: [pull_request,push]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node: [ '10', '12', '14' ]
+ name: Test on Node ${{ matrix.node }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup node
+ uses: actions/setup-node@v2
+ with:
+ node-version: ${{ matrix.node }}
+ - run: npm install
+ - run: npm test
\ No newline at end of file
diff --git a/jalangi2/.gitignore b/jalangi2/.gitignore
new file mode 100644
index 00000000000..9946b25f380
--- /dev/null
+++ b/jalangi2/.gitignore
@@ -0,0 +1,3 @@
+.idea
+node_modules
+*~
diff --git a/jalangi2/.npmignore b/jalangi2/.npmignore
new file mode 100644
index 00000000000..6de5cc88c2e
--- /dev/null
+++ b/jalangi2/.npmignore
@@ -0,0 +1,3 @@
+tests
+.travis.yml
+.gitignore
\ No newline at end of file
diff --git a/jalangi2/.travis.yml b/jalangi2/.travis.yml
new file mode 100644
index 00000000000..e5c4680bfb2
--- /dev/null
+++ b/jalangi2/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+ - "10"
+ - "12"
+ - "14.2.0"
+sudo: false
\ No newline at end of file
diff --git a/jalangi2/LICENSE.txt b/jalangi2/LICENSE.txt
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/jalangi2/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/jalangi2/README.md b/jalangi2/README.md
new file mode 100644
index 00000000000..8e82d454e2a
--- /dev/null
+++ b/jalangi2/README.md
@@ -0,0 +1,155 @@
+Jalangi2
+=======
+### Introduction
+
+Jalangi2 is a framework for writing dynamic analyses for JavaScript.
+Jalangi1 is still available at https://github.com/SRA-SiliconValley/jalangi, but we no longer plan to develop it.
+Jalangi2 does not support the record/replay feature of Jalangi1.
+In the Jalangi2 distribution you will find several analyses:
+
+ * an analysis to [track NaNs](src/js/sample_analyses/dlint/CheckNaN.js).
+ * an analysis to [check if an undefined is concatenated to a string](src/js/sample_analyses/dlint/ConcatUndefinedToString.js).
+ * [Memory analysis](https://github.com/Samsung/meminsight): a memory-profiler for JavaScript and HTML5.
+ * [DLint](https://github.com/ksen007/jalangi2analyses): a dynamic checker for JavaScript bad coding practices.
+ * [JITProf](https://github.com/ksen007/jalangi2analyses): a dynamic JIT-unfriendly code snippet detection tool.
+ * [analysisCallbackTemplate.js](src/js/runtime/analysisCallbackTemplate.js): a template for writing a dynamic analysis.
+ * and [more ...](src/js/sample_analyses/)
+
+See [our tutorial slides](http://manu.sridharan.net/files/JalangiTutorial.pdf) for a detailed overview of Jalangi and some client analyses.
+
+### Requirements
+
+We have tested Jalangi on Mac OS X with Chromium browser. Jalangi should work on Mac OS
+10.7, Ubuntu 11.0 and higher and Windows 7 or higher. Jalangi will NOT work with IE.
+
+ * Node.js available at https://nodejs.org/en/download/releases/. We primarily test Jalangi with the Node LTS version (currently v12).
+ * Chrome browser if you need to test web apps.
+ * Python (http://python.org) version 3.x.
+
+On Windows you need the following extra dependencies:
+
+ * Install Microsoft Visual Studio 2010 (Free express version is fine).
+ * If on 64bit also install Windows 7 64-bit SDK.
+
+If you have a fresh installation of Ubuntu, you can install all the requirements by invoking the following commands from a terminal
+(package names may be out of date).
+
+ sudo apt-get update
+ sudo apt-get install python-software-properties python g++ make
+ sudo add-apt-repository ppa:chris-lea/node.js
+ sudo apt-get update
+ sudo apt-get install nodejs
+ sudo apt-get update
+ sudo apt-get install chromium-browser
+
+### Installation
+
+Clone the repository, and then run:
+
+ npm install
+
+### Run tests
+
+ python scripts/test.traceall.py
+ python scripts/test.analysis.py
+ python scripts/test.dlint.py
+
+### Usage
+
+**Analysis in node.js with on-the-fly instrumentation**
+
+An analysis can be performed on a JavaScript file in node.js by issuing the following commands:
+
+ node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/ChainedAnalyses.js --analysis src/js/sample_analyses/dlint/Utils.js --analysis src/js/sample_analyses/dlint/CheckNaN.js --analysis src/js/sample_analyses/dlint/FunCalledWithMoreArguments.js --analysis src/js/sample_analyses/dlint/CompareFunctionWithPrimitives.js --analysis src/js/sample_analyses/dlint/ShadowProtoProperty.js --analysis src/js/sample_analyses/dlint/ConcatUndefinedToString.js --analysis src/js/sample_analyses/dlint/UndefinedOffset.js tests/octane/deltablue.js
+
+In the above analysis, we chained several analyses by including *--analysis src/js/analyses/ChainedAnalyses.js* as the first analysis.
+The command runs the following analyses
+
+ src/js/sample_analyses/dlint/CheckNaN.js
+ src/js/sample_analyses/dlint/FunCalledWithMoreArguments.js
+ src/js/sample_analyses/dlint/CompareFunctionWithPrimitives.js
+ src/js/sample_analyses/dlint/ShadowProtoProperty.js
+ src/js/sample_analyses/dlint/ConcatUndefinedToString.js
+ src/js/sample_analyses/dlint/UndefinedOffset.js
+
+The implementation of an analysis requires the implementation of several callback functions. One can start writing
+an writing analysis using the template file [src/js/runtime/analysisCallbackTemplate.js](src/js/runtime/analysisCallbackTemplate.js).
+A documentation of these call back functions can be found at [docs/MyAnalysis.html](docs/MyAnalysis.html).
+A tutorial on writing a Jalangi analysis can be found at [docs/tutorial1.md](docs/tutorial1.md). While writing
+an analysis one could run [src/js/sample_analyses/pldi16/TraceAll.js](src/js/sample_analyses/pldi16/TraceAll.js)
+analysis on a JavaScript file to print all the callback functions that got
+called during the execution of the file. Such a trace is useful to see what callbacks get called during an
+execution. The following command runs the TraceAll.js analysis on the file [tests/octane/deltablue.js](tests/octane/deltablue.js).
+
+ node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/ChainedAnalyses.js --analysis src/js/runtime/SMemory.js --analysis src/js/sample_analyses/pldi16/TraceAll.js tests/octane/deltablue.js
+
+**Analysis in node.js with explicit one-file-at-a-time offline instrumentation**
+
+An analysis can be performed on a JavaScript file in node.js by issuing the following commands:
+
+ node src/js/commands/esnstrument_cli.js --inlineIID --inlineSource tests/octane/deltablue.js
+ node src/js/commands/direct.js --analysis src/js/sample_analyses/ChainedAnalyses.js --analysis src/js/sample_analyses/dlint/Utils.js --analysis src/js/sample_analyses/dlint/CheckNaN.js --analysis src/js/sample_analyses/dlint/FunCalledWithMoreArguments.js --analysis src/js/sample_analyses/dlint/CompareFunctionWithPrimitives.js --analysis src/js/sample_analyses/dlint/ShadowProtoProperty.js --analysis src/js/sample_analyses/dlint/ConcatUndefinedToString.js --analysis src/js/sample_analyses/dlint/UndefinedOffset.js tests/octane/deltablue_jalangi_.js
+
+In the above analysis, we chained several analyses by including *--analysis src/js/analyses/ChainedAnalyses.js*.
+
+**Analysis in a browser using offline instrumentation**
+
+An analysis can be performed on a web app using the Chrome browser by issuing the following commands:
+
+ node src/js/commands/instrument.js --inlineIID --inlineSource -i --inlineJalangi --analysis src/js/sample_analyses/ChainedAnalyses.js --analysis src/js/sample_analyses/dlint/Utils.js --analysis src/js/sample_analyses/dlint/CheckNaN.js --analysis src/js/sample_analyses/dlint/FunCalledWithMoreArguments.js --analysis src/js/sample_analyses/dlint/CompareFunctionWithPrimitives.js --analysis src/js/sample_analyses/dlint/ShadowProtoProperty.js --analysis src/js/sample_analyses/dlint/ConcatUndefinedToString.js --analysis src/js/sample_analyses/dlint/UndefinedOffset.js --outputDir /tmp tests/tizen/annex
+ open file:///tmp/annex/index.html
+
+While performing analysis in a browser, one needs to press Alt-Shift-T to end the analysis and to print the analysis results in the console.
+
+**Analysis in a browser using a proxy and on-the-fly instrumentation**
+
+You can also setup a proxy to instrument JavaScript files on-the-fly.
+To do so, you need to install [mitmproxy](http://mitmproxy.org/). We have tested mitmproxy version 7.0.
+On Linux, you can follow
+[the standard installation instructions](http://docs.mitmproxy.org/en/stable/install.html),
+but instead of running `sudo pip install mitmproxy`, run `sudo pip install mitmproxy==7.0.0` to get the tested version. On Mac OS,
+the easiest path we have found is to use [Homebrew](http://brew.sh/).
+With Homebrew installed, you can install the right version by running:
+
+ brew install python
+ pip install -U pip
+ pip install mitmproxy==7.0.0
+
+Note that you might need to restart your shell afterward, to ensure
+the python being used is `/usr/local/bin/python`.
+
+For instrumenting code served over HTTPS, you will additionally need
+to set up a root certificate for mitmproxy. See
+[their instructions](http://docs.mitmproxy.org/en/stable/certinstall.html)
+or [this document](https://github.com/ksen007/jalangi2analyses/blob/master/doc/mitmproxy-install.pdf).
+
+After installation, you can run the Jalangi instrumentation proxy by
+issuing the following command:
+
+ mitmdump --quiet --anticache -s "scripts/proxy.py --inlineIID --inlineSource --analysis src/js/sample_analyses/ChainedAnalyses.js --analysis src/js/runtime/analysisCallbackTemplate.js"
+
+In your browser, the http and https proxy should be set to 127.0.0.1:8080. Now if you load a website in your browser, all JavaScript files associated with the website will get instrumented on-the-fly.
+
+On a Mac, the proxy can be set and launched automatically by issuing the following command:
+
+ ./scripts/mitmproxywrapper.py --toggle --auto-disable --quiet --anticache -s "scripts/proxy.py --inlineIID --inlineSource --analysis src/js/sample_analyses/ChainedAnalyses.js --analysis src/js/runtime/analysisCallbackTemplate.js"
+
+The command starts mitmproxy if the proxy is not currently enabled, and disables it otherwise.
+The `--auto-disable` option will automatically disable the proxy when the script is interrupted.
+
+Jalangi2 caches the instrumented source files in `./cache/`.
+The use of the cache can be disabled during development by passing the `--no-cache` flag to `scripts/proxy.py`.
+
+### Developing an analysis in Jalangi2
+
+Refer to [docs/index.html](docs/index.html) and [docs/commands.md](docs/commands.md) for further information. A tutorial
+on writing a Jalangi analysis can be found in [docs/tutorial1.md](docs/tutorial1.md).
+
+### Supported ECMAScript versions
+
+Jalangi2 supports ECMAScript 5.1. Some ES6 features may work, but have not been tested.
+
+License
+-------
+
+Jalangi2 is distributed under the [Apache License](http://www.apache.org/licenses/LICENSE-2.0.html).
diff --git a/jalangi2/conf.json b/jalangi2/conf.json
new file mode 100644
index 00000000000..cda1f81af4c
--- /dev/null
+++ b/jalangi2/conf.json
@@ -0,0 +1,29 @@
+{
+ "tags": {
+ "allowUnknownTags": true
+ },
+ "source": {
+ "includePattern": ".+\\.js(doc)?$",
+ "excludePattern": "(^|\\/|\\\\)_"
+ },
+ "plugins": [],
+ "templates": {
+ "applicationName": "Jalangi 2",
+ "disqus": "",
+ "googleAnalytics": "",
+ "openGraph": {
+ "title": "",
+ "type": "website",
+ "image": "",
+ "site_name": "",
+ "url": ""
+ },
+ "meta": {
+ "title": "",
+ "description": "",
+ "keyword": ""
+ },
+ "linenums": true
+ }
+}
+
diff --git a/jalangi2/docs/MyAnalysis.html b/jalangi2/docs/MyAnalysis.html
new file mode 100644
index 00000000000..642569d2016
--- /dev/null
+++ b/jalangi2/docs/MyAnalysis.html
@@ -0,0 +1,6798 @@
+
+
+
+ This file is a template for writing a custom Jalangi 2 analysis. Simply copy this file and rewrite the
+ callbacks that you need to implement in your analysis. Other callbacks should be removed from the file.
+
+
+
+ In the following methods (also called as callbacks) one can choose to not return anything.
+ If all of the callbacks return nothing, we get a passive analysis where the
+ concrete execution happens unmodified and callbacks can be used to observe the execution.
+ One can choose to return suitable objects with specified properties in some callbacks
+ to modify the behavior of the concrete execution. For example, one could set the skip
+ property of the object returned from MyAnalysis#putFieldPre to true to skip the actual putField operation.
+ Similarly, one could set the result field of the object returned from a MyAnalysis#write callback
+ to modify the value that is actually written to a variable. The result field of the object
+ returned from a MyAnalysis#conditional callback can be suitably set to change the control-flow of the
+ program execution. In MyAnalysis#functionExit and MyAnalysis#scriptExit,
+ one can set the isBacktrack property of the returned object to true to reexecute the body of
+ the function from the beginning. This in conjunction with the ability to change the
+ control-flow of a program enables us to explore the different paths of a function in
+ symbolic execution.
+
+
+
+ Note that if process.exit() is called, then an execution terminates abnormally and a callback to
+ MyAnalysis#endExecution will be skipped.
+
+
+
+ An analysis can access the source map, which maps instruction identifiers to source locations,
+ using the global object stored in J$.smap. Jalangi 2
+ assigns a unique id, called sid, to each JavaScript
+ script loaded at runtime. J$.smap maps each sid to an object, say
+ iids, containing source map information for the script whose id is sid.
+ iids has the following properties: "originalCodeFileName" (stores the path of the original
+ script file), "instrumentedCodeFileName" (stores the path of the instrumented script file),
+ "url" (is optional and stores the URL of the script if it is set during instrumentation
+ using the --url option),
+ "evalSid" (stores the sid of the script in which the eval is called in case the current script comes from
+ an eval function call),
+ "evalIid" (iid of the eval function call in case the current script comes from an
+ eval function call), "nBranches" (the number of conditional statements
+ in the script),
+ and "code" (a string denoting the original script code if the code is instrumented with the
+ --inlineSource option).
+ iids also maps each iid (which stands for instruction id, an unique id assigned
+ to each callback function inserted by Jalangi2) to an array containing
+ [beginLineNumber, beginColumnNumber, endLineNumber, endColumnNumber]. The mapping from iids
+ to arrays is only available if the code is instrumented with
+ the --inlineIID option.
+
+
+ In each callback described below, iid denotes the unique static instruction id of the callback in the script.
+ Two callback functions inserted in two different scripts may have the same iid. In a callback function, one can access
+ the current script id using J$.sid. One can call J$.getGlobalIID(iid) to get a string, called
+ giid, that statically identifies the
+ callback throughout the program. J$.getGlobalIID(iid) returns the string J$.sid+":"+iid.
+ J$.iidToLocation(giid) returns a string
+ containing the original script file path, begin and end line numbers and column numbers of the code snippet
+ for which the callback with giid was inserted.
+
+
+
+ A number of sample analyses can be found at ../src/js/sample_analyses/. Refer to ../README.md for instructions
+ on running an analysis.
+
+ This callback is called after a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
+<<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
op
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ Operation to be performed
+
+
+
+
+
+
+
left
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Left operand
+
+
+
+
+
+
+
right
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Right operand
+
+
+
+
+
+
+
result
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ The result of the binary operation
+
+
+
+
+
+
+
isOpAssign
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the binary operation is part of an expression of the form
+x op= e
+
+
+
+
+
+
+
isSwitchCaseComparison
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the binary operation is part of comparing the discriminant
+with a consequent in a switch statement.
+
+
+
+
+
+
+
isComputed
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the operation is of the form delete x[p], and false
+otherwise (even if the operation if of the form delete x.p)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned, the result of the binary operation is
+replaced with the value stored in the result property of the object.
+ This callback is called before a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
+<<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in. No callback for delete x
+because this operation cannot be performed reflectively.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
op
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ Operation to be performed
+
+
+
+
+
+
+
left
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Left operand
+
+
+
+
+
+
+
right
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Right operand
+
+
+
+
+
+
+
isOpAssign
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the binary operation is part of an expression of the form
+x op= e
+
+
+
+
+
+
+
isSwitchCaseComparison
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the binary operation is part of comparing the discriminant
+with a consequent in a switch statement.
+
+
+
+
+
+
+
isComputed
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the operation is of the form delete x[p], and false
+otherwise (even if the operation if of the form delete x.p)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned and the
+skip property is true, then the binary operation is skipped. Original op, left,
+and right are replaced with that from the returned object if an object is returned.
+ This callback is called after a condition check before branching. Branching can happen in various statements
+including if-then-else, switch-case, while, for, ||, &&, ?:.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
result
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ The value of the conditional expression
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned, the result of the conditional expression is
+replaced with the value stored in the result property of the object.
+ This callback is triggered at the beginning of a scope for every local variable declared in the scope, for
+every formal parameter, for every function defined using a function statement, for arguments
+variable, and for the formal parameter passed in a catch statement.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
name
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ Name of the variable that is declared
+
+
+
+
+
+
+
val
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Initial value of the variable that is declared. Variables can be local variables, function
+parameters, catch parameters, arguments, or functions defined using function statements. Variables
+declared with var have undefined as initial values and cannot be changed by returning a
+different value from this callback. On the beginning of an execution of a function, a declare
+callback is called on the arguments variable.
+
+
+
+
+
+
+
isArgument
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the variable is arguments or a formal parameter.
+
+
+
+
+
+
+
argumentIndex
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Index of the argument in the function call. Indices start from 0. If the
+variable is not a formal parameter, then argumentIndex is -1.
+
+
+
+
+
+
+
isCatchParam
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the variable is a parameter of a catch statement.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If the function returns an object, then the original initial value is
+replaced with the value stored in the result property of the object. This does not apply to local
+variables declared with var.
+ This callback is called when an execution terminates in node.js. In a browser environment, the callback is
+called if ChainedAnalyses.js or ChainedAnalysesNoCheck.js is used and Alt-Shift-T is pressed.
+
+ This callback is called when an expression is evaluated and its value is discarded. For example, this
+callback is called when an expression statement completes its execution.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+ This callback is called when a for-in loop is used to iterate the properties of an object.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
val
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Objects whose properties are iterated in a for-in loop.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If the function returns an object, then the original object whose
+properties are being iterated is replaced with the value stored in the result property of the
+returned object.
+
+
+
+
+
+
+
+
+
Example
+
+
+
+
for (x in y) { }
+
+// the above call roughly gets instrumented as follows:
+
+var aret = analysis.forinObject(iid, y);
+if (aret) {
+ y = aret.result;
+}
+for (x in y) {}
+ This callback is called when the execution of a function body completes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
returnVal
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ The value returned by the function
+
+
+
+
+
+
+
wrappedExceptionVal
+
+
+
+
+
+Object
+|
+
+undefined
+
+
+
+
+
+
+
+
+
+ If this parameter is an object, the function
+execution has thrown an uncaught exception and the exception is being stored in the exception
+property of the parameter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+
+
+
+
If an object is returned, then the
+actual returnVal and wrappedExceptionVal.exception are replaced with that from the
+returned object. If an object is returned and the property isBacktrack is set, then the control-flow
+returns to the beginning of the function body instead of returning to the caller. The property
+isBacktrack can be set to true to repeatedly execute the function body as in MultiSE
+symbolic execution.
+ This callback is called after a property of an object is accessed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
base
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Base object
+
+
+
+
+
+
+
offset
+
+
+
+
+
+string
+|
+
+*
+
+
+
+
+
+
+
+
+
+ Property
+
+
+
+
+
+
+
val
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Value of base[offset]
+
+
+
+
+
+
+
isComputed
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if property is accessed using square brackets. For example,
+isComputed is true if the get field operation is o[p], and false
+if the get field operation is o.p
+
+
+
+
+
+
+
isOpAssign
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the operation is of the form o.p op= e
+
+
+
+
+
+
+
isMethodCall
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the get field operation is part of a method call (e.g. o.p())
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned, the value of the get field operation is
+replaced with the value stored in the result property of the object.
+ This callback is called before a property of an object is accessed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
base
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Base object
+
+
+
+
+
+
+
offset
+
+
+
+
+
+string
+|
+
+*
+
+
+
+
+
+
+
+
+
+ Property
+
+
+
+
+
+
+
isComputed
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if property is accessed using square brackets. For example,
+isComputed is true if the get field operation is o[p], and false
+if the get field operation is o.p
+
+
+
+
+
+
+
isOpAssign
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the operation is of the form o.p op= e
+
+
+
+
+
+
+
isMethodCall
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the get field operation is part of a method call (e.g. o.p())
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned and the skip
+property of the object is true, then the get field operation is skipped. Original base and
+offset are replaced with that from the returned object if an object is returned.
+ This callback is called before a string passed as an argument to eval or Function is instrumented.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
code
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Code that is going to get instrumented
+
+
+
+
+
+
+
isDirect
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ true if this is a direct call to eval
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+
+
+
+
- If an object is returned and the
+skip property is true, then the instrumentation of code is skipped.
+Original code is replaced with that from the returned object if an object is returned.
+ This callback is called after a function, method, or constructor invocation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
f
+
+
+
+
+
+function
+
+
+
+
+
+
+
+
+
+ The function object that was invoked
+
+
+
+
+
+
+
base
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ The receiver object for the function f
+
+
+
+
+
+
+
args
+
+
+
+
+
+Array
+
+
+
+
+
+
+
+
+
+ The array of arguments passed to f
+
+
+
+
+
+
+
result
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ The value returned by the invocation
+
+
+
+
+
+
+
isConstructor
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if f is invoked as a constructor
+
+
+
+
+
+
+
isMethod
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if f is invoked as a method
+
+
+
+
+
+
+
functionIid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ The iid (i.e. the unique instruction identifier) where the function was created
+
+
+
+
+
+
+
functionSid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ The sid (i.e. the unique script identifier) where the function was created
+MyAnalysis#functionEnter when the function f is executed. functionIid can be treated as the
+static identifier of the function f. Note that a given function code block can create several function
+objects, but each such object has a common functionIid, which is the iid that is passed to
+MyAnalysis#functionEnter when the function executes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned, the return value of the invoked function is
+replaced with the value stored in the result property of the object. This enables one to change the
+value that is returned by the actual function invocation.
+
+
+
+
+
+
+
+
+
Example
+
+
+
+
x = y.f(a, b, c)
+
+// the above call roughly gets instrumented as follows:
+
+var skip = false;
+var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true);
+if (aret) {
+ f = aret.f;
+ y = aret.y;
+ args = aret.args;
+ skip = aret.skip
+}
+if (!skip) {
+ result =f.apply(y, args);
+}
+aret = analysis.invokeFun(117, f, y, args, result, false, true);
+if (aret) {
+ x = aret.result
+} else {
+ x = result;
+}
+ This callback is called before a function, method, or constructor invocation.
+Note that a method invocation also triggers a MyAnalysis#getFieldPre and a
+MyAnalysis#getField callbacks.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
f
+
+
+
+
+
+function
+
+
+
+
+
+
+
+
+
+ The function object that going to be invoked
+
+
+
+
+
+
+
base
+
+
+
+
+
+object
+
+
+
+
+
+
+
+
+
+ The receiver object for the function f
+
+
+
+
+
+
+
args
+
+
+
+
+
+Array
+
+
+
+
+
+
+
+
+
+ The array of arguments passed to f
+
+
+
+
+
+
+
isConstructor
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if f is invoked as a constructor
+
+
+
+
+
+
+
isMethod
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if f is invoked as a method
+
+
+
+
+
+
+
functionIid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ The iid (i.e. the unique instruction identifier) where the function was created
+
+
+
+
+
+
+
functionSid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ The sid (i.e. the unique script identifier) where the function was created
+MyAnalysis#functionEnter when the function f is executed. The functionIid can be
+treated as the static identifier of the function f. Note that a given function code block can
+create several function objects, but each such object has a common functionIid, which is the iid
+that is passed to MyAnalysis#functionEnter when the function executes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned and
+the skip property of the object is true, then the invocation operation is skipped.
+Original f, base, and args are replaced with that from the returned object if
+an object is returned.
+
+
+
+
+
+
+
+
+
Example
+
+
+
+
y.f(a, b, c)
+
+// the above call roughly gets instrumented as follows:
+
+var skip = false;
+var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true);
+if (aret) {
+ f = aret.f;
+ y = aret.y;
+ args = aret.args;
+ skip = aret.skip
+}
+if (!skip) {
+ f.apply(y, args);
+}
+ This callback is called after the creation of a literal. A literal can be a function literal, an object literal,
+an array literal, a number, a string, a boolean, a regular expression, null, NaN, Infinity, or undefined.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
val
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ The literal value
+
+
+
+
+
+
+
hasGetterSetter
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the literal is an object and the object defines getters and setters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If the function returns an object, then the original literal value is
+replaced with the value stored in the result property of the object.
+
+
+
+
+
+
+
+
+
Example
+
+
+
+
x = "Hello"
+
+// the above call roughly gets instrumented as follows:
+
+var result = "Hello";
+var aret = analysis.literal(201, result, false);
+if (aret) {
+ result = aret.result;
+}
+x = result;
+ onReady is useful if your analysis is running on node.js (i.e., via the direct.js or jalangi.js commands)
+and needs to complete some asynchronous initialization before the instrumented program starts. In such a
+case, once the initialization is complete, invoke the cb function to start execution of the instrumented
+program.
+
+Note that this callback is not useful in the browser, as Jalangi has no control over when the
+instrumented program runs there.
+
+ This callback is called after a property of an object is written.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
base
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Base object
+
+
+
+
+
+
+
offset
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Property
+
+
+
+
+
+
+
val
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Value to be stored in base[offset]
+
+
+
+
+
+
+
isComputed
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if property is accessed using square brackets. For example,
+isComputed is true if the get field operation is o[p], and false
+if the get field operation is o.p
+
+
+
+
+
+
+
isOpAssign
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the operation is of the form o.p op= e
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned, the result of the put field operation is
+replaced with the value stored in the result property of the object.
+ This callback is called before a property of an object is written.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
base
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Base object
+
+
+
+
+
+
+
offset
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Property
+
+
+
+
+
+
+
val
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Value to be stored in base[offset]
+
+
+
+
+
+
+
isComputed
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if property is accessed using square brackets. For example,
+isComputed is true if the get field operation is o[p], and false
+if the get field operation is o.p
+
+
+
+
+
+
+
isOpAssign
+
+
+
+
+
+boolean
+
+
+
+
+
+
+
+
+
+ True if the operation is of the form o.p op= e
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- If an object is returned and the skip
+property is true, then the put field operation is skipped. Original base, offset, and
+val are replaced with that from the returned object if an object is returned.
+ This callback is called only when instrumented with J$.Config.ENABLE_SAMPLING = true
+This callback is called before the body of a function, method, or constructor is executed
+if returns true, instrumented function body is executed, else uninstrumented function body is executed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
f
+
+
+
+
+
+function
+
+
+
+
+
+
+
+
+
+ The function whose body is being executed
+
+
+
+
+
+
+
functionIid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ The iid (i.e. the unique instruction identifier) where the function was created
+
+
+
+
+
+
+
functionSid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ The sid (i.e. the unique script identifier) where the function was created
+MyAnalysis#functionEnter when the function f is executed. The functionIid can be
+treated as the static identifier of the function f. Note that a given function code block can
+create several function objects, but each such object has a common functionIid, which is the iid
+that is passed to MyAnalysis#functionEnter when the function executes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ boolean
+
+
+
+
- If true is returned the instrumented function body is executed, otherwise the
+uninstrumented function body is executed.
+ This callback is called when the execution of a JavaScript file completes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
wrappedExceptionVal
+
+
+
+
+
+Object
+|
+
+undefined
+
+
+
+
+
+
+
+
+
+ If this parameter is an object, the script
+execution has thrown an uncaught exception and the exception is being stored in the exception
+property of the parameter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+
+
+
+
- If an object is returned, then the
+actual wrappedExceptionVal.exception is replaced with that from the
+returned object. If an object is returned and the property isBacktrack is set, then the control-flow
+returns to the beginning of the script body. The property
+isBacktrack can be set to true to repeatedly execute the script body as in MultiSE
+symbolic execution.
+ This callback is called before a unary operation. Unary operations include +, -, ~, !, typeof, void.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
iid
+
+
+
+
+
+number
+
+
+
+
+
+
+
+
+
+ Static unique instruction identifier of this callback
+
+
+
+
+
+
+
op
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ Operation to be performed
+
+
+
+
+
+
+
left
+
+
+
+
+
+*
+
+
+
+
+
+
+
+
+
+ Left operand
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
If an object is returned and the
+skip property is true, then the unary operation is skipped. Original op and left
+are replaced with that from the returned object if an object is returned.
+SMemory associates a unique object with every JavaScript object, function, and activation frame during an execution.
+(Note that a shadow object cannot associated with primitive values, undefined, or null.) A shadow object can be used
+to store meta-information about an object (e.g. the location at which the object was created). Each shadow
+object has an unique id, which can be treated as the logical address of the corresponding JavaScript object or
+activation frame.
+
+To use smemory, one must include --analysis $JALANGI_HOME/src/js/sample_analyses/ChainedAnalyses.js
+--analysis $JALANGI_HOME/src/js/runtime/SMemory.js as the first two --analysis options during an analysis.
+smemory can be accessed via J$.smemory or sandbox.smemory. The smemory object defines several methods.
+Those methods can be used to obtain the shadow memory for an object property or a program variable,
+respectively. getShadowObject should be used in getFieldPre, putFieldPre, and literal callbacks. (In a literal
+callback with an object literal, one must go over all the own properties of the literal object to suitably update
+shadow object.) getShadowFrame should only be used in declare, read, and write callbacks.
+
+ This method returns the shadow object associated with the activation frame that contains the variable "name". To get the current activation frame,
+call J$.smemory.getFrame("this");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
name
+
+
+
+
+
+
+
+
+
+
+ Name of the variable whose owner activation frame's shadow object we want to retrieve
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+
+
+
+
- The shadow object of the activation frame owning the variable.
+ Given a shadow object or frame, it returns the unique id of the shadow object or frame. It returns undefined,
+if obj is undefined, null, or not a valid shadow object.
+
+ This method should be called on a base object and a property name to retrieve the shadow object associated with
+the object that actually owns the
+property. When the program performs a putField operation, the third argument should be false and the returned
+object is the shadow object associated with the base object. When the program performs a getField operation,
+the third argument should be true and the returned object is the shadow object associated with the object in the
+prototype chain (or the base object) which owns the property. For a getField operation, the returned value
+is undefined if none of the
+objects in the prototype chain owns the property. The return value is an object with two properties: "owner"
+points to the shadow object and "isProperty" indicates if the property is a concrete property of the object or
+if the property denotes a getter/setter.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
obj
+
+
+
+
+
+
+
+
+
+
+ The base object
+
+
+
+
+
+
+
prop
+
+
+
+
+
+
+
+
+
+
+ The property name
+
+
+
+
+
+
+
isGetField
+
+
+
+
+
+
+
+
+
+
+ True if the property access is a getField operation
+ This method returns the shadow object associated with the argument. If the argument cannot be associated with a shadow
+object, the function returns undefined.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
val
+
+
+
+
+
+
+
+
+
+
+ The object whose shadow object the function returns
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
+
+
+
Type
+
Description
+
+
+
+
+
+
+
+
+ Object
+ |
+
+ undefined
+
+
+
+
- Returns the shadow object associated with val. Return undefined if there is no shadow object assocaited with val
+Note that a shadow object cannot be associated with a primitive value: number, string, boolean, undefined, or null.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jalangi2/docs/analysis.md b/jalangi2/docs/analysis.md
new file mode 100644
index 00000000000..d01945630b0
--- /dev/null
+++ b/jalangi2/docs/analysis.md
@@ -0,0 +1,5 @@
+### Writing a Jalangi2 analysis ###
+
+**Work in progress**
+
+In this tutorial, we will describe how to develop and run a simple analysis in Jalangi 2.
diff --git a/jalangi2/docs/commands.md b/jalangi2/docs/commands.md
new file mode 100644
index 00000000000..132153773ff
--- /dev/null
+++ b/jalangi2/docs/commands.md
@@ -0,0 +1,150 @@
+## jalangi.js
+
+Command-line utility to perform Jalangi2's instrumentation and analysis
+
+ node src/js/commands/jalangi.js -h
+ usage: jalangi.js [-h] [--analysis ANALYSIS] [--initParam INITPARAM]
+ [--inlineIID] [--inlineSource]
+ [--astHandlerModule ASTHANDLERMODULE]
+ ...
+
+
+Positional arguments:
+
+ script_and_args script to record and CLI arguments for that script
+
+Optional arguments:
+
+ -h, --help Show this help message and exit.
+ --analysis ANALYSIS absolute path to analysis file to run
+ --initParam INITPARAM
+ initialization parameter for analysis, specified as
+ key:value
+ --inlineIID Inline IID to (beginLineNo, beginColNo, endLineNo,
+ endColNo) in J$.iids in the instrumented file
+ --inlineSource Inline original source as string in J$.iids.code in
+ the instrumented file
+ --astHandlerModule ASTHANDLERMODULE
+ Path to a node module that exports a function to be
+ used for additional AST handling after instrumentation
+
+## esnstrument_cli.js
+
+Command-line utility to perform instrumentation
+
+ node src/js/commands/esnstrument_cli.js -h
+ usage: esnstrument_cli.js [-h] [--inlineIID] [--inlineSource]
+ [--initParam INITPARAM] [--noResultsGUI]
+ [--astHandlerModule ASTHANDLERMODULE]
+ [--outDir OUTDIR] [--out OUT] [--url URL]
+ [--extra_app_scripts EXTRA_APP_SCRIPTS]
+ [--analysis ANALYSIS]
+ file
+
+
+Positional arguments:
+
+ file file to instrument
+
+Optional arguments:
+
+ -h, --help Show this help message and exit.
+ --inlineIID Inline IID to (beginLineNo, beginColNo, endLineNo,
+ endColNo) in J$.iids in the instrumented file
+ --inlineSource Inline original source as string in J$.iids.code in
+ the instrumented file
+ --initParam INITPARAM
+ initialization parameter for analysis, specified as
+ key:value
+ --noResultsGUI disable insertion of results GUI code in HTML
+ --astHandlerModule ASTHANDLERMODULE
+ Path to a node module that exports a function to be
+ used for additional AST handling after instrumentation
+ --outDir OUTDIR Directory containing scripts inlined in html
+ --out OUT Instrumented file name (with path). The default is to
+ append _jalangi_ to the original JS file name
+ --url URL URL of the file to be instrumented. The URL is stored
+ as metadata in the source map and is not used for
+ retrieving the file.
+ --extra_app_scripts EXTRA_APP_SCRIPTS
+ list of extra application scripts to be injected and
+ instrumented, separated by path.delimiter
+ --analysis ANALYSIS Analysis script.
+
+## instrument.js
+
+Utility to apply Jalangi instrumentation to files or a folder.
+
+ node src/js/commands/instrument.js -h
+ usage: instrument.js [-h] [-x EXCLUDE] [--only_include ONLY_INCLUDE] [-i]
+ [--inlineIID] [--inlineSource] [--inlineJalangi]
+ [--analysis ANALYSIS] [--initParam INITPARAM] [-d] [-c]
+ [--extra_app_scripts EXTRA_APP_SCRIPTS] [--no_html]
+ --outputDir OUTPUTDIR [--verbose]
+ [--astHandlerModule ASTHANDLERMODULE]
+ inputFiles[inputFiles ...]
+
+
+Positional arguments:
+
+ inputFiles either a list of JavaScript files to instrument, or a
+ single directory under which all JavaScript and HTML
+ files should be instrumented (modulo the --no_html
+ and --exclude flags)
+
+Optional arguments:
+
+ -h, --help Show this help message and exit.
+ -x EXCLUDE, --exclude EXCLUDE
+ do not instrument any scripts whose file path
+ contains this substring
+ --only_include ONLY_INCLUDE
+ list of path prefixes specifying which
+ sub-directories should be instrumented, separated by
+ path.delimiter
+ -i, --instrumentInline
+ instrument inline scripts
+ --inlineIID Inline IID to (beginLineNo, beginColNo, endLineNo,
+ endColNo) in J$.iids in the instrumented file
+ --inlineSource Inline original source as string in J$.iids.code in
+ the instrumented file
+ --inlineJalangi Inline Jalangi runtime source code into HTML files
+ --analysis ANALYSIS Analysis script.
+ --initParam INITPARAM
+ initialization parameter for analysis, specified as
+ key:value
+ -d, --direct_in_output
+ Store instrumented app directly in output directory
+ (by default, creates a sub-directory of output
+ directory)
+ -c, --copy_runtime Copy Jalangi runtime files into instrumented app in
+ jalangi_rt sub-directory
+ --extra_app_scripts EXTRA_APP_SCRIPTS
+ list of extra application scripts to be injected and
+ instrumented, separated by path.delimiter
+ --no_html don't inject Jalangi runtime into HTML files
+ --outputDir OUTPUTDIR
+ directory in which to place instrumented files
+ --verbose print verbose output
+ --astHandlerModule ASTHANDLERMODULE
+ Path to a node module that exports a function to be
+ used for additional AST handling after instrumentation
+## direct.js
+
+Command-line utility to perform Jalangi2's analysis
+
+ node src/js/commands/direct.js -h
+ usage: direct.js [-h] [--analysis ANALYSIS] [--initParam INITPARAM] ...
+
+
+Positional arguments:
+
+ script_and_args script to record and CLI arguments for that script
+
+Optional arguments:
+
+ -h, --help Show this help message and exit.
+ --analysis ANALYSIS absolute path to analysis file to run
+ --initParam INITPARAM
+ initialization parameter for analysis, specified as
+ key:value
diff --git a/jalangi2/docs/fonts/glyphicons-halflings-regular.eot b/jalangi2/docs/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 00000000000..423bd5d3a20
Binary files /dev/null and b/jalangi2/docs/fonts/glyphicons-halflings-regular.eot differ
diff --git a/jalangi2/docs/fonts/glyphicons-halflings-regular.svg b/jalangi2/docs/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 00000000000..44694887478
--- /dev/null
+++ b/jalangi2/docs/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+
+
+
\ No newline at end of file
diff --git a/jalangi2/docs/fonts/glyphicons-halflings-regular.ttf b/jalangi2/docs/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 00000000000..a498ef4e7c8
Binary files /dev/null and b/jalangi2/docs/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/jalangi2/docs/fonts/glyphicons-halflings-regular.woff b/jalangi2/docs/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000000..d83c539b826
Binary files /dev/null and b/jalangi2/docs/fonts/glyphicons-halflings-regular.woff differ
diff --git a/jalangi2/docs/index.html b/jalangi2/docs/index.html
new file mode 100644
index 00000000000..bf897222b8b
--- /dev/null
+++ b/jalangi2/docs/index.html
@@ -0,0 +1,360 @@
+
+
+
+
+ Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jalangi2/src/js/runtime/SMemory.js b/jalangi2/src/js/runtime/SMemory.js
new file mode 100644
index 00000000000..184964b4ddd
--- /dev/null
+++ b/jalangi2/src/js/runtime/SMemory.js
@@ -0,0 +1,356 @@
+
+/**
+ * @file A library to associate shadow objects and unique ids to JavaScript objects and activation frames.
+ * @author Koushik Sen
+ *
+ */
+
+(function (sandbox) {
+ /**
+ *
+ * SMemory associates a unique object with every JavaScript object, function, and activation frame during an execution.
+ * (Note that a shadow object cannot associated with primitive values, undefined, or null.) A shadow object can be used
+ * to store meta-information about an object (e.g. the location at which the object was created). Each shadow
+ * object has an unique id, which can be treated as the logical address of the corresponding JavaScript object or
+ * activation frame.
+ *
+ * To use smemory, one must include --analysis $JALANGI_HOME/src/js/sample_analyses/ChainedAnalyses.js
+ * --analysis $JALANGI_HOME/src/js/runtime/SMemory.js as the first two --analysis options during an analysis.
+ * smemory can be accessed via J$.smemory or sandbox.smemory. The smemory object defines several methods.
+ * Those methods can be used to obtain the shadow memory for an object property or a program variable,
+ * respectively. getShadowObject should be used in getFieldPre, putFieldPre, and literal callbacks. (In a literal
+ * callback with an object literal, one must go over all the own properties of the literal object to suitably update
+ * shadow object.) getShadowFrame should only be used in declare, read, and write callbacks.
+ *
+ *
+ * @global
+ * @class
+ */
+ function SMemory() {
+ var Constants = sandbox.Constants;
+
+ var PREFIX = Constants.JALANGI_VAR;
+ var SPECIAL_PROP_SOBJECT = "*" + PREFIX + "O*";
+ var SPECIAL_PROP_FRAME = "*" + PREFIX + "F*";
+ var SPECIAL_PROP_ACTUAL = "*" + PREFIX + "A*";
+ var objectId = 1;
+ var frameId = 2;
+ var scriptCount = 0;
+ var HOP = Constants.HOP;
+
+
+ var frame = Object.create(null);
+
+ var frameStack = [frame];
+ var evalFrames = [];
+
+ var processEnv = !sandbox.Constants.isBrowser && process && process.env;
+ var shadowEnv = Object.create(null);
+ if (processEnv) {
+ shadowEnv[SPECIAL_PROP_SOBJECT] = objectId;
+ shadowEnv[SPECIAL_PROP_ACTUAL] = process.env;
+ objectId += 2;
+ }
+
+
+ // public function
+ /**
+ * This method should be called on a base object and a property name to retrieve the shadow object associated with
+ * the object that actually owns the
+ * property. When the program performs a putField operation, the third argument should be false and the returned
+ * object is the shadow object associated with the base object. When the program performs a getField operation,
+ * the third argument should be true and the returned object is the shadow object associated with the object in the
+ * prototype chain (or the base object) which owns the property. For a getField operation, the returned value
+ * is undefined if none of the
+ * objects in the prototype chain owns the property. The return value is an object with two properties: "owner"
+ * points to the shadow object and "isProperty" indicates if the property is a concrete property of the object or
+ * if the property denotes a getter/setter.
+ *
+ * @param obj - The base object
+ * @param prop - The property name
+ * @param isGetField - True if the property access is a getField operation
+ * @returns {{owner: Object, isProperty: boolean}}
+ */
+ this.getShadowObject = function (obj, prop, isGetField) {
+ var ownerAndAccess = getOwnerAndAccess(obj, prop, isGetField);
+ if (ownerAndAccess.owner !== undefined) {
+ ownerAndAccess.owner = this.getShadowObjectOfObject(ownerAndAccess.owner);
+ }
+ return ownerAndAccess;
+ };
+
+ // public function
+ /**
+ * This method returns the shadow object associated with the activation frame that contains the variable "name".
+ *
+ * @param name - Name of the variable whose owner activation frame's shadow object we want to retrieve
+ * @returns {Object} - The shadow object of the activation frame owning the variable.
+ */
+ this.getShadowFrame = function (name) {
+ var f = this.getFrame(name);
+ var ret = this.getShadowObjectOfObject(f);
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(ret, SPECIAL_PROP_ACTUAL, {
+ enumerable: false,
+ writable: true
+ });
+ }
+ ret[SPECIAL_PROP_ACTUAL] = f[SPECIAL_PROP_ACTUAL];
+ return ret;
+ };
+
+ // public function
+ /**
+ * Given a shadow object or frame, it returns the unique id of the shadow object or frame. It returns undefined,
+ * if obj is undefined, null, or not a valid shadow object.
+ * @param obj
+ * @returns {number|undefined}
+ */
+
+ this.getIDFromShadowObjectOrFrame = function (obj) {
+ if (obj === undefined || obj === null) return undefined;
+ return obj[SPECIAL_PROP_SOBJECT];
+ };
+
+ // public function
+ /**
+ * Given a shadow object, it returns the actual object.
+ * Given a shadow frame, it returns the function whose invocation created the frame.
+ *
+ * @param obj
+ * @returns {*}
+ */
+ this.getActualObjectOrFunctionFromShadowObjectOrFrame = function (obj) {
+ return obj[SPECIAL_PROP_ACTUAL];
+ };
+
+
+ /**
+ * This method returns the shadow object associated with the activation frame that contains the variable "name". To get the current activation frame,
+ * call J$.smemory.getFrame("this");
+ *
+ * @param name - Name of the variable whose owner activation frame's shadow object we want to retrieve
+ * @returns {Object} - The shadow object of the activation frame owning the variable.
+ */
+ this.getFrame = function (name) {
+ var tmp = frame;
+ while (tmp && !HOP(tmp, name)) {
+ tmp = tmp[SPECIAL_PROP_FRAME];
+ }
+ if (tmp) {
+ return tmp;
+ } else {
+ return frameStack[0]; // return global scope
+ }
+ };
+
+
+ /**
+ * This method returns the shadow object associated with the argument. If the argument cannot be associated with a shadow
+ * object, the function returns undefined.
+ *
+ * @param val - The object whose shadow object the function returns
+ * @returns {Object|undefined} - Returns the shadow object associated with val. Return undefined if there is no shadow object assocaited with val
+ * Note that a shadow object cannot be associated with a primitive value: number, string, boolean, undefined, or null.
+ */
+ this.getShadowObjectOfObject = function (val) {
+ if (processEnv && val === process.env) {
+ return shadowEnv;
+ }
+ var value;
+ createShadowObject(val);
+ var type = typeof val;
+ if ((type === 'object' || type === 'function') && val !== null && HOP(val, SPECIAL_PROP_SOBJECT)) {
+ if (typeof val[SPECIAL_PROP_SOBJECT] === 'object') {
+ value = val[SPECIAL_PROP_SOBJECT];
+ }
+ } else {
+ value = undefined;
+ }
+ return value;
+ };
+
+
+
+ function getOwnerAndAccess(obj, prop, isGetField) {
+ if (typeof Object.getOwnPropertyDescriptor !== 'function') {
+ throw new Error("Cannot call getOwnPropertyDescriptor on Object.");
+ }
+ var oldObj = obj;
+ while (obj !== null) {
+ if (typeof obj !== 'object' && typeof obj !== 'function') {
+ return false;
+ }
+ var desc = Object.getOwnPropertyDescriptor(obj, prop);
+ if (desc !== undefined) {
+ if (isGetField && typeof desc.get === 'function') {
+ return {"owner": obj, "isProperty": false};
+ }
+ if (!isGetField && typeof desc.set === 'function') {
+ return {"owner": obj, "isProperty": false};
+ }
+ }
+ if (isGetField && HOP(obj, prop)) {
+ return {"owner": obj, "isProperty": true};
+ }
+ obj = obj.__proto__;
+ }
+ if (!isGetField) {
+ return {"owner": oldObj, "isProperty": true};
+ } else {
+ return {"owner": undefined, "isProperty": true};
+ }
+ }
+
+ function createShadowObject(val) {
+ var type = typeof val;
+ if ((type === 'object' || type === 'function') && val !== null && !HOP(val, SPECIAL_PROP_SOBJECT)) {
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(val, SPECIAL_PROP_SOBJECT, {
+ enumerable: false,
+ writable: true
+ });
+ Object.defineProperty(val, SPECIAL_PROP_ACTUAL, {
+ enumerable: false,
+ writable: true
+ });
+ }
+ try {
+ val[SPECIAL_PROP_SOBJECT] = Object.create(null);
+ val[SPECIAL_PROP_SOBJECT][SPECIAL_PROP_SOBJECT] = objectId;
+ val[SPECIAL_PROP_SOBJECT][SPECIAL_PROP_ACTUAL] = val;
+ objectId = objectId + 2;
+ } catch (e) {
+ // cannot attach special field in some DOM Objects. So ignore them.
+ }
+ }
+
+ }
+
+ this.defineFunction = function (f) {
+ if (typeof f === 'function') {
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(f, SPECIAL_PROP_FRAME, {
+ enumerable: false,
+ writable: true
+ });
+ }
+ f[SPECIAL_PROP_FRAME] = frame;
+ }
+ };
+
+ //this.evalBegin = function (isDirect) {
+ // evalFrames.push(frame);
+ // if (!isDirect)
+ // frame = frameStack[0];
+ //};
+
+ //this.evalEnd = function () {
+ // frame = evalFrames.pop();
+ //};
+
+
+ this.initialize = function (name) {
+ frame[name] = undefined;
+ };
+
+ this.functionEnter = function (val) {
+ frameStack.push(frame = Object.create(null));
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(frame, SPECIAL_PROP_FRAME, {
+ enumerable: false,
+ writable: true
+ });
+ Object.defineProperty(frame, SPECIAL_PROP_ACTUAL, {
+ enumerable: false,
+ writable: true
+ });
+ }
+ frame[SPECIAL_PROP_FRAME] = val[SPECIAL_PROP_FRAME];
+ frame[SPECIAL_PROP_ACTUAL] = val;
+ };
+
+ this.functionReturn = function () {
+ frameStack.pop();
+ frame = frameStack[frameStack.length - 1];
+ };
+
+ var isEvalScript = [];
+
+ this.scriptEnter = function (instrumentedFileName, originalFileName) {
+ scriptCount++;
+ if (scriptCount > 0) {
+ if (!(originalFileName === 'eval' && instrumentedFileName === originalFileName)) {
+ if (Constants.isBrowser) {
+ frame = frameStack[0];
+ } else {
+ frameStack.push(frame = Object.create(null));
+ frame[SPECIAL_PROP_FRAME] = frameStack[0];
+ }
+ isEvalScript.push(false);
+ } else {
+ isEvalScript.push(true);
+ }
+ }
+ };
+
+ this.scriptReturn = function () {
+ if (scriptCount > 0 && !isEvalScript.pop()) {
+ if (!Constants.isBrowser) {
+ frameStack.pop();
+ }
+ frame = frameStack[frameStack.length - 1];
+ }
+ scriptCount--;
+ };
+
+ }
+
+ var smemory = sandbox.smemory = new SMemory();
+
+ function MyAnalysis() {
+ this.literal = function (iid, val, hasGetterSetter) {
+ smemory.defineFunction(val);
+ };
+
+ this.declare = function (iid, name, val, isArgument, argumentIndex, isCatchParam) {
+ smemory.initialize(name);
+ };
+
+ this.functionEnter = function (iid, f, dis, args) {
+ smemory.functionEnter(f);
+ smemory.initialize('this');
+ };
+
+
+ this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
+ smemory.functionReturn();
+ };
+
+
+ this.scriptEnter = function (iid, instrumentedFileName, originalFileName) {
+ smemory.scriptEnter(instrumentedFileName, originalFileName);
+ };
+
+ this.scriptExit = function (iid, wrappedExceptionVal) {
+ smemory.scriptReturn();
+ };
+
+
+ //this.instrumentCodePre = function (iid, code, isDirect) {
+ // smemory.evalBegin(isDirect);
+ //};
+ //
+ //
+ //this.instrumentCode = function (iid, newCode, newAst, isDirect) {
+ // console.log(newCode);
+ // smemory.evalEnd(isDirect);
+ //};
+
+ }
+
+ sandbox.analysis = new MyAnalysis();
+
+}(J$));
+
+
diff --git a/jalangi2/src/js/runtime/analysis.js b/jalangi2/src/js/runtime/analysis.js
new file mode 100644
index 00000000000..804dfbd04a8
--- /dev/null
+++ b/jalangi2/src/js/runtime/analysis.js
@@ -0,0 +1,811 @@
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+
+// wrap in anonymous function to create local namespace when in browser
+// create / reset J$ global variable to hold analysis runtime
+if (typeof J$ === 'undefined') {
+ J$ = {};
+}
+
+(function (sandbox) {
+ if (typeof sandbox.B !== 'undefined') {
+ return;
+ }
+ //----------------------------------- Begin Jalangi Library backend ---------------------------------
+
+ // stack of return values from instrumented functions.
+ // we need to keep a stack since a function may return and then
+ // have another function call in a finally block (see test
+ // call_in_finally.js)
+
+ var global = this;
+ var Function = global.Function;
+ var returnStack = [];
+ var wrappedExceptionVal;
+ var lastVal;
+ var switchLeft;
+ var switchKeyStack = [];
+ var argIndex;
+ var EVAL_ORG = eval;
+ var lastComputedValue;
+ var SPECIAL_PROP_SID = sandbox.Constants.SPECIAL_PROP_SID;
+ var SPECIAL_PROP_IID = sandbox.Constants.SPECIAL_PROP_IID;
+
+ function getPropSafe(base, prop){
+ if(base === null || base === undefined){
+ return undefined;
+ }
+ return base[prop];
+ }
+
+ function decodeBitPattern(i, len) {
+ var ret = new Array(len);
+ for (var j=0; j> 1;
+ }
+ return ret;
+ }
+
+ function createBitPattern() {
+ var ret = 0;
+ var i;
+ for (i =0; i< arguments.length; i++) {
+ ret = (ret << 1)+(arguments[i]?1:0);
+ }
+ return ret;
+ }
+
+
+ var sidStack = [], sidCounter = 0;
+
+ function createAndAssignNewSid() {
+ sidStack.push(sandbox.sid);
+ sandbox.sid = sidCounter = sidCounter + 1;
+ if (!sandbox.smap) sandbox.smap = {};
+ sandbox.smap[sandbox.sid] = sandbox.iids;
+ }
+
+ function rollBackSid() {
+ sandbox.sid = sidStack.pop();
+ }
+
+ function associateSidWithFunction(f, iid) {
+ if (typeof f === 'function') {
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(f, SPECIAL_PROP_SID, {
+ enumerable:false,
+ writable:true
+ });
+ Object.defineProperty(f, SPECIAL_PROP_IID, {
+ enumerable:false,
+ writable:true
+ });
+ }
+ f[SPECIAL_PROP_SID] = sandbox.sid;
+ f[SPECIAL_PROP_IID] = iid;
+ }
+ }
+
+ function updateSid(f) {
+ sidStack.push(sandbox.sid);
+ sandbox.sid = getPropSafe(f, SPECIAL_PROP_SID);
+ }
+
+
+ // unused
+ function isNative(f) {
+ return f.toString().indexOf('[native code]') > -1 || f.toString().indexOf('[object ') === 0;
+ }
+
+ function callAsNativeConstructorWithEval(Constructor, args) {
+ var a = [];
+ for (var i = 0; i < args.length; i++)
+ a[i] = 'args[' + i + ']';
+ var myEval = eval;
+ return myEval('new Constructor(' + a.join() + ')');
+ }
+
+ function callAsNativeConstructor(Constructor, args) {
+ if (args.length === 0) {
+ return new Constructor();
+ }
+ if (args.length === 1) {
+ return new Constructor(args[0]);
+ }
+ if (args.length === 2) {
+ return new Constructor(args[0], args[1]);
+ }
+ if (args.length === 3) {
+ return new Constructor(args[0], args[1], args[2]);
+ }
+ if (args.length === 4) {
+ return new Constructor(args[0], args[1], args[2], args[3]);
+ }
+ if (args.length === 5) {
+ return new Constructor(args[0], args[1], args[2], args[3], args[4]);
+ }
+ return callAsNativeConstructorWithEval(Constructor, args);
+ }
+
+ function callAsConstructor(Constructor, args) {
+ var ret;
+ if (true) {
+ ret = callAsNativeConstructor(Constructor, args);
+ return ret;
+ } else { // else branch is a more elegant to call a constructor reflectively, but it leads to memory leak in v8.
+ var Temp = function () {
+ }, inst;
+ Temp.prototype = Constructor.prototype;
+ inst = new Temp;
+ ret = Constructor.apply(inst, args);
+ return Object(ret) === ret ? ret : inst;
+ }
+ }
+
+ function invokeEval(base, f, args, iid) {
+ return f(sandbox.instrumentEvalCode(args[0], iid, false));
+ }
+
+ function invokeFunctionDecl(base, f, args, iid) {
+ // Invoke with the original parameters to preserve exceptional behavior if input is invalid
+ f.apply(base, args);
+ // Otherwise input is valid, so instrument and invoke via eval
+ var newArgs = [];
+ for (var i = 0; i < args.length-1; i++) {
+ newArgs[i] = args[i];
+ }
+ var code = '(function(' + newArgs.join(', ') + ') { ' + args[args.length-1] + ' })';
+ var code = sandbox.instrumentEvalCode(code, iid, false);
+ // Using EVAL_ORG instead of eval() is important as it preserves the scoping semantics of Function()
+ var out = EVAL_ORG(code);
+ return out;
+ }
+
+ function callFun(f, base, args, isConstructor, iid) {
+ var result;
+ pushSwitchKey();
+ try {
+ if (f === EVAL_ORG) {
+ result = invokeEval(base, f, args, iid);
+ } else if (f === Function) {
+ result = invokeFunctionDecl(base, f, args, iid);
+ } else if (isConstructor) {
+ result = callAsConstructor(f, args);
+ } else {
+ result = Function.prototype.apply.call(f, base, args);
+ }
+ return result;
+ } finally {
+ popSwitchKey();
+ }
+ }
+
+ function invokeFun(iid, base, f, args, isConstructor, isMethod) {
+ var aret, skip = false, result;
+
+ if (sandbox.analysis && sandbox.analysis.invokeFunPre) {
+ aret = sandbox.analysis.invokeFunPre(iid, f, base, args, isConstructor, isMethod, getPropSafe(f, SPECIAL_PROP_IID), getPropSafe(f, SPECIAL_PROP_SID));
+ if (aret) {
+ f = aret.f;
+ base = aret.base;
+ args = aret.args;
+ skip = aret.skip;
+ }
+ }
+ if (!skip) {
+ result = callFun(f, base, args, isConstructor, iid);
+ }
+ if (sandbox.analysis && sandbox.analysis.invokeFun) {
+ aret = sandbox.analysis.invokeFun(iid, f, base, args, result, isConstructor, isMethod, getPropSafe(f, SPECIAL_PROP_IID), getPropSafe(f, SPECIAL_PROP_SID));
+ if (aret) {
+ result = aret.result;
+ }
+ }
+ return result;
+ }
+
+ // Function call (e.g., f())
+ function F(iid, f, flags) {
+ var bFlags = decodeBitPattern(flags, 1); // [isConstructor]
+ return function () {
+ var base = this;
+ return (lastComputedValue = invokeFun(iid, base, f, arguments, bFlags[0], false));
+ }
+ }
+
+ // Method call (e.g., e.f())
+ function M(iid, base, offset, flags) {
+ var bFlags = decodeBitPattern(flags, 2); // [isConstructor, isComputed]
+ var f = G(iid + 2, base, offset, createBitPattern(bFlags[1], false, true));
+ return function () {
+ return (lastComputedValue = invokeFun(iid, base, f, arguments, bFlags[0], true));
+ };
+ }
+
+ // Ignore argument (identity).
+ function I(val) {
+ return val;
+ }
+
+ var hasGetOwnPropertyDescriptor = typeof Object.getOwnPropertyDescriptor === 'function';
+ // object/function/regexp/array Literal
+ function T(iid, val, type, hasGetterSetter, internalIid) {
+ var aret;
+ associateSidWithFunction(val, internalIid);
+ if (hasGetterSetter) {
+ for (var offset in val) {
+ if (hasGetOwnPropertyDescriptor && val.hasOwnProperty(offset)) {
+ var desc = Object.getOwnPropertyDescriptor(val, offset);
+ if (desc !== undefined) {
+ if (typeof desc.get === 'function') {
+ T(iid, desc.get, 12, false, internalIid);
+ }
+ if (typeof desc.set === 'function') {
+ T(iid, desc.set, 12, false, internalIid);
+ }
+ }
+ }
+ }
+ }
+ if (sandbox.analysis && sandbox.analysis.literal) {
+ aret = sandbox.analysis.literal(iid, val, hasGetterSetter);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return (lastComputedValue = val);
+ }
+
+ // wrap object o in for (x in o) { ... }
+ function H(iid, val) {
+ var aret;
+ if (sandbox.analysis && sandbox.analysis.forinObject) {
+ aret = sandbox.analysis.forinObject(iid, val);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return val;
+ }
+
+ // variable declaration (Init)
+ function N(iid, name, val, flags) {
+ var bFlags = decodeBitPattern(flags, 3); // [isArgument, isLocalSync, isCatchParam]
+ // isLocalSync is only true when we sync variables inside a for-in loop
+ var aret;
+
+ if (bFlags[0]) {
+ argIndex++;
+ }
+ if (!bFlags[1] && sandbox.analysis && sandbox.analysis.declare) {
+ if (bFlags[0] && argIndex > 1) {
+ aret = sandbox.analysis.declare(iid, name, val, bFlags[0], argIndex - 2, bFlags[2]);
+ } else {
+ aret = sandbox.analysis.declare(iid, name, val, bFlags[0], -1, bFlags[2]);
+ }
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return val;
+ }
+
+ // getField (property read)
+ function G(iid, base, offset, flags) {
+ var bFlags = decodeBitPattern(flags, 3); // [isComputed, isOpAssign, isMethodCall]
+
+ var aret, skip = false, val;
+
+ if (sandbox.analysis && sandbox.analysis.getFieldPre) {
+ aret = sandbox.analysis.getFieldPre(iid, base, offset, bFlags[0], bFlags[1], bFlags[2]);
+ if (aret) {
+ base = aret.base;
+ offset = aret.offset;
+ skip = aret.skip;
+ }
+ }
+
+ if (!skip) {
+ val = base[offset];
+ }
+ if (sandbox.analysis && sandbox.analysis.getField) {
+ aret = sandbox.analysis.getField(iid, base, offset, val, bFlags[0], bFlags[1], bFlags[2]);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return (lastComputedValue = val);
+ }
+
+ // putField (property write)
+ function P(iid, base, offset, val, flags) {
+ var bFlags = decodeBitPattern(flags, 2); // [isComputed, isOpAssign]
+
+ var aret, skip = false;
+
+ if (sandbox.analysis && sandbox.analysis.putFieldPre) {
+ aret = sandbox.analysis.putFieldPre(iid, base, offset, val, bFlags[0], !!bFlags[1]);
+ if (aret) {
+ base = aret.base;
+ offset = aret.offset;
+ val = aret.val;
+ skip = aret.skip;
+ }
+ }
+
+ if (!skip) {
+ base[offset] = val;
+ }
+ if (sandbox.analysis && sandbox.analysis.putField) {
+ aret = sandbox.analysis.putField(iid, base, offset, val, bFlags[0], !!bFlags[1]);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return (lastComputedValue = val);
+ }
+
+ // variable write
+ // isGlobal means that the variable is global and not declared as var
+ // isScriptLocal means that the variable is global and is declared as var
+ function R(iid, name, val, flags) {
+ var aret;
+ var bFlags = decodeBitPattern(flags, 2); // [isGlobal, isScriptLocal]
+
+ if (sandbox.analysis && sandbox.analysis.read) {
+ aret = sandbox.analysis.read(iid, name, val, bFlags[0], bFlags[1]);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return (lastComputedValue = val);
+ }
+
+ // variable write
+ function W(iid, name, val, lhs, flags) {
+ var bFlags = decodeBitPattern(flags, 3); //[isGlobal, isScriptLocal, isDeclaration]
+ var aret;
+ if (sandbox.analysis && sandbox.analysis.write) {
+ aret = sandbox.analysis.write(iid, name, val, lhs, bFlags[0], bFlags[1]);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ if (!bFlags[2]) {
+ return (lastComputedValue = val);
+ } else {
+ lastComputedValue = undefined;
+ return val;
+ }
+ }
+
+ // with statement
+ function Wi(iid, val) {
+ if (sandbox.analysis && sandbox.analysis._with) {
+ aret = sandbox.analysis._with(iid, val);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return val;
+ }
+
+ // Uncaught exception
+ function Ex(iid, e) {
+ wrappedExceptionVal = {exception:e};
+ }
+
+ // Throw statement
+ function Th(iid, val) {
+ var aret;
+ if (sandbox.analysis && sandbox.analysis._throw) {
+ aret = sandbox.analysis._throw(iid, val);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ return (lastComputedValue = val);
+ }
+
+ // Return statement
+ function Rt(iid, val) {
+ var aret;
+ if (sandbox.analysis && sandbox.analysis._return) {
+ aret = sandbox.analysis._return(iid, val);
+ if (aret) {
+ val = aret.result;
+ }
+ }
+ returnStack.pop();
+ returnStack.push(val);
+ return (lastComputedValue = val);
+ }
+
+ // Actual return from function, invoked from 'finally' block
+ // added around every function by instrumentation. Reads
+ // the return value stored by call to Rt()
+ function Ra() {
+ var returnVal = returnStack.pop();
+ wrappedExceptionVal = undefined;
+ return returnVal;
+ }
+
+ // Function enter
+ function Fe(iid, f, dis /* this */, args) {
+ argIndex = 0;
+ returnStack.push(undefined);
+ wrappedExceptionVal = undefined;
+ updateSid(f);
+ if (sandbox.analysis && sandbox.analysis.functionEnter) {
+ sandbox.analysis.functionEnter(iid, f, dis, args);
+ }
+ }
+
+ // Function exit
+ function Fr(iid) {
+ var isBacktrack = false, tmp, aret, returnVal;
+
+ returnVal = returnStack.pop();
+ if (sandbox.analysis && sandbox.analysis.functionExit) {
+ aret = sandbox.analysis.functionExit(iid, returnVal, wrappedExceptionVal);
+ if (aret) {
+ returnVal = aret.returnVal;
+ wrappedExceptionVal = aret.wrappedExceptionVal;
+ isBacktrack = aret.isBacktrack;
+ }
+ }
+ rollBackSid();
+ if (!isBacktrack) {
+ returnStack.push(returnVal);
+ }
+ // if there was an uncaught exception, throw it
+ // here, to preserve exceptional control flow
+ if (wrappedExceptionVal !== undefined) {
+ tmp = wrappedExceptionVal.exception;
+ wrappedExceptionVal = undefined;
+ throw tmp;
+ }
+ return isBacktrack;
+ }
+
+ // Script enter
+ function Se(iid, val, origFileName) {
+ createAndAssignNewSid();
+ if (sandbox.analysis && sandbox.analysis.scriptEnter) {
+ sandbox.analysis.scriptEnter(iid, val, origFileName);
+ }
+ lastComputedValue = undefined;
+ }
+
+ // Script exit
+ function Sr(iid) {
+ var tmp, aret, isBacktrack;
+ if (sandbox.analysis && sandbox.analysis.scriptExit) {
+ aret = sandbox.analysis.scriptExit(iid, wrappedExceptionVal);
+ if (aret) {
+ wrappedExceptionVal = aret.wrappedExceptionVal;
+ isBacktrack = aret.isBacktrack;
+ }
+ }
+ rollBackSid();
+ if (wrappedExceptionVal !== undefined) {
+ tmp = wrappedExceptionVal.exception;
+ wrappedExceptionVal = undefined;
+ throw tmp;
+ }
+ return isBacktrack;
+ }
+
+
+ // Modify and assign +=, -= ...
+ function A(iid, base, offset, op, flags) {
+ var bFlags = decodeBitPattern(flags, 1); // [isComputed]
+ // avoid iid collision: make sure that iid+2 has the same source map as iid (@todo)
+ var oprnd1 = G(iid+2, base, offset, createBitPattern(bFlags[0], true, false));
+ return function (oprnd2) {
+ // still possible to get iid collision with a mem operation
+ var val = B(iid, op, oprnd1, oprnd2, createBitPattern(false, true, false));
+ return P(iid, base, offset, val, createBitPattern(bFlags[0], true));
+ };
+ }
+
+ // Binary operation
+ function B(iid, op, left, right, flags) {
+ var bFlags = decodeBitPattern(flags, 3); // [isComputed, isOpAssign, isSwitchCaseComparison]
+ var result, aret, skip = false;
+
+ if (sandbox.analysis && sandbox.analysis.binaryPre) {
+ aret = sandbox.analysis.binaryPre(iid, op, left, right, bFlags[1], bFlags[2], bFlags[0]);
+ if (aret) {
+ op = aret.op;
+ left = aret.left;
+ right = aret.right;
+ skip = aret.skip;
+ }
+ }
+
+
+ if (!skip) {
+ switch (op) {
+ case "+":
+ result = left + right;
+ break;
+ case "-":
+ result = left - right;
+ break;
+ case "*":
+ result = left * right;
+ break;
+ case "/":
+ result = left / right;
+ break;
+ case "%":
+ result = left % right;
+ break;
+ case "<<":
+ result = left << right;
+ break;
+ case ">>":
+ result = left >> right;
+ break;
+ case ">>>":
+ result = left >>> right;
+ break;
+ case "<":
+ result = left < right;
+ break;
+ case ">":
+ result = left > right;
+ break;
+ case "<=":
+ result = left <= right;
+ break;
+ case ">=":
+ result = left >= right;
+ break;
+ case "==":
+ result = left == right;
+ break;
+ case "!=":
+ result = left != right;
+ break;
+ case "===":
+ result = left === right;
+ break;
+ case "!==":
+ result = left !== right;
+ break;
+ case "&":
+ result = left & right;
+ break;
+ case "|":
+ result = left | right;
+ break;
+ case "^":
+ result = left ^ right;
+ break;
+ case "delete":
+ result = delete left[right];
+ break;
+ case "instanceof":
+ result = left instanceof right;
+ break;
+ case "in":
+ result = left in right;
+ break;
+ default:
+ throw new Error(op + " at " + iid + " not found");
+ break;
+ }
+ }
+
+ if (sandbox.analysis && sandbox.analysis.binary) {
+ aret = sandbox.analysis.binary(iid, op, left, right, result, bFlags[1], bFlags[2], bFlags[0]);
+ if (aret) {
+ result = aret.result;
+ }
+ }
+ return (lastComputedValue = result);
+ }
+
+
+ // Unary operation
+ function U(iid, op, left) {
+ var result, aret, skip = false;
+
+ if (sandbox.analysis && sandbox.analysis.unaryPre) {
+ aret = sandbox.analysis.unaryPre(iid, op, left);
+ if (aret) {
+ op = aret.op;
+ left = aret.left;
+ skip = aret.skip
+ }
+ }
+
+ if (!skip) {
+ switch (op) {
+ case "+":
+ result = +left;
+ break;
+ case "-":
+ result = -left;
+ break;
+ case "~":
+ result = ~left;
+ break;
+ case "!":
+ result = !left;
+ break;
+ case "typeof":
+ result = typeof left;
+ break;
+ case "void":
+ result = void(left);
+ break;
+ default:
+ throw new Error(op + " at " + iid + " not found");
+ break;
+ }
+ }
+
+ if (sandbox.analysis && sandbox.analysis.unary) {
+ aret = sandbox.analysis.unary(iid, op, left, result);
+ if (aret) {
+ result = aret.result;
+ }
+ }
+ return (lastComputedValue = result);
+ }
+
+ function pushSwitchKey() {
+ switchKeyStack.push(switchLeft);
+ }
+
+ function popSwitchKey() {
+ switchLeft = switchKeyStack.pop();
+ }
+
+ function last() {
+ return (lastComputedValue = lastVal);
+ }
+
+ // Switch key
+ // E.g., for 'switch (x) { ... }',
+ // C1 is invoked with value of x
+ function C1(iid, left) {
+ switchLeft = left;
+ return (lastComputedValue = left);
+ }
+
+ // case label inside switch
+ function C2(iid, right) {
+ var aret, result;
+
+ // avoid iid collision; iid may not have a map in the sourcemap
+ result = B(iid+1, "===", switchLeft, right, createBitPattern(false, false, true));
+
+ if (sandbox.analysis && sandbox.analysis.conditional) {
+ aret = sandbox.analysis.conditional(iid, result);
+ if (aret) {
+ if (result && !aret.result) {
+ right = !right;
+ } else if (result && aret.result) {
+ right = switchLeft;
+ }
+ }
+ }
+ return (lastComputedValue = right);
+ }
+
+ // Expression in conditional
+ function C(iid, left) {
+ var aret;
+ if (sandbox.analysis && sandbox.analysis.conditional) {
+ aret = sandbox.analysis.conditional(iid, left);
+ if (aret) {
+ left = aret.result;
+ }
+ }
+
+ lastVal = left;
+ return (lastComputedValue = left);
+ }
+
+ function S(iid, f) {
+ if (sandbox.analysis && sandbox.analysis.runInstrumentedFunctionBody) {
+ return sandbox.analysis.runInstrumentedFunctionBody(iid, f, getPropSafe(f, SPECIAL_PROP_IID), getPropSafe(f, SPECIAL_PROP_SID));
+ }
+ return true;
+ }
+
+ function L() {
+ return lastComputedValue;
+ }
+
+
+ function X1(iid, val) {
+ if (sandbox.analysis && sandbox.analysis.endExpression) {
+ sandbox.analysis.endExpression(iid);
+ }
+
+ return (lastComputedValue = val);
+ }
+
+ function endExecution() {
+ if (sandbox.analysis && sandbox.analysis.endExecution) {
+ return sandbox.analysis.endExecution();
+ }
+ }
+
+
+ function log(str) {
+ if (sandbox.Results && sandbox.Results.execute) {
+ sandbox.Results.execute(function(div, jquery, editor){
+ div.append(str+" ");
+ });
+ } else {
+ console.log(str);
+ }
+ }
+
+
+ //----------------------------------- End Jalangi Library backend ---------------------------------
+
+ sandbox.U = U; // Unary operation
+ sandbox.B = B; // Binary operation
+ sandbox.C = C; // Condition
+ sandbox.C1 = C1; // Switch key
+ sandbox.C2 = C2; // case label C1 === C2
+ sandbox._ = last; // Last value passed to C
+
+ sandbox.H = H; // hash in for-in
+ sandbox.I = I; // Ignore argument
+ sandbox.G = G; // getField
+ sandbox.P = P; // putField
+ sandbox.R = R; // Read
+ sandbox.W = W; // Write
+ sandbox.N = N; // Init
+ sandbox.T = T; // object/function/regexp/array Literal
+ sandbox.F = F; // Function call
+ sandbox.M = M; // Method call
+ sandbox.A = A; // Modify and assign +=, -= ...
+ sandbox.Fe = Fe; // Function enter
+ sandbox.Fr = Fr; // Function return
+ sandbox.Se = Se; // Script enter
+ sandbox.Sr = Sr; // Script return
+ sandbox.Rt = Rt; // returned value
+ sandbox.Th = Th; // thrown value
+ sandbox.Ra = Ra;
+ sandbox.Ex = Ex;
+ sandbox.L = L;
+ sandbox.X1 = X1; // top level expression
+ sandbox.Wi = Wi; // with statement
+ sandbox.endExecution = endExecution;
+
+ sandbox.S = S;
+
+ sandbox.EVAL_ORG = EVAL_ORG;
+ sandbox.log = log;
+})(J$);
+
diff --git a/jalangi2/src/js/runtime/analysisCallbackTemplate.js b/jalangi2/src/js/runtime/analysisCallbackTemplate.js
new file mode 100644
index 00000000000..0f2f999a487
--- /dev/null
+++ b/jalangi2/src/js/runtime/analysisCallbackTemplate.js
@@ -0,0 +1,646 @@
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+/**
+ * @file A template for writing a Jalangi 2 analysis
+ * @author Koushik Sen
+ *
+ */
+
+(function (sandbox) {
+ /**
+ *
+ * This file is a template for writing a custom Jalangi 2 analysis. Simply copy this file and rewrite the
+ * callbacks that you need to implement in your analysis. Other callbacks should be removed from the file.
+ *
+ *
+ *
+ * In the following methods (also called as callbacks) one can choose to not return anything.
+ * If all of the callbacks return nothing, we get a passive analysis where the
+ * concrete execution happens unmodified and callbacks can be used to observe the execution.
+ * One can choose to return suitable objects with specified properties in some callbacks
+ * to modify the behavior of the concrete execution. For example, one could set the skip
+ * property of the object returned from {@link MyAnalysis#putFieldPre} to true to skip the actual putField operation.
+ * Similarly, one could set the result field of the object returned from a {@link MyAnalysis#write} callback
+ * to modify the value that is actually written to a variable. The result field of the object
+ * returned from a {@link MyAnalysis#conditional} callback can be suitably set to change the control-flow of the
+ * program execution. In {@link MyAnalysis#functionExit} and {@link MyAnalysis#scriptExit},
+ * one can set the isBacktrack property of the returned object to true to reexecute the body of
+ * the function from the beginning. This in conjunction with the ability to change the
+ * control-flow of a program enables us to explore the different paths of a function in
+ * symbolic execution.
+ *
+ *
+ *
+ * Note that if process.exit() is called, then an execution terminates abnormally and a callback to
+ * {@link MyAnalysis#endExecution} will be skipped.
+ *
+ *
+ *
+ * An analysis can access the source map, which maps instruction identifiers to source locations,
+ * using the global object stored in J$.smap. Jalangi 2
+ * assigns a unique id, called sid, to each JavaScript
+ * script loaded at runtime. J$.smap maps each sid to an object, say
+ * iids, containing source map information for the script whose id is sid.
+ * iids has the following properties: "originalCodeFileName" (stores the path of the original
+ * script file), "instrumentedCodeFileName" (stores the path of the instrumented script file),
+ * "url" (is optional and stores the URL of the script if it is set during instrumentation
+ * using the --url option),
+ * "evalSid" (stores the sid of the script in which the eval is called in case the current script comes from
+ * an eval function call),
+ * "evalIid" (iid of the eval function call in case the current script comes from an
+ * eval function call), "nBranches" (the number of conditional statements
+ * in the script),
+ * and "code" (a string denoting the original script code if the code is instrumented with the
+ * --inlineSource option).
+ * iids also maps each iid (which stands for instruction id, an unique id assigned
+ * to each callback function inserted by Jalangi2) to an array containing
+ * [beginLineNumber, beginColumnNumber, endLineNumber, endColumnNumber]. The mapping from iids
+ * to arrays is only available if the code is instrumented with
+ * the --inlineIID option.
+ *
+ *
+ * In each callback described below, iid denotes the unique static instruction id of the callback in the script.
+ * Two callback functions inserted in two different scripts may have the same iid. In a callback function, one can access
+ * the current script id using J$.sid. One can call J$.getGlobalIID(iid) to get a string, called
+ * giid, that statically identifies the
+ * callback throughout the program. J$.getGlobalIID(iid) returns the string J$.sid+":"+iid.
+ * J$.iidToLocation(giid) returns a string
+ * containing the original script file path, begin and end line numbers and column numbers of the code snippet
+ * for which the callback with giid was inserted.
+ *
+ *
+ *
+ * A number of sample analyses can be found at {@link ../src/js/sample_analyses/}. Refer to {@link ../README.md} for instructions
+ * on running an analysis.
+ *
+ *
+ *
+ *
+ * @global
+ * @class
+ */
+ function MyAnalysis() {
+ /**
+ * This callback is called before a function, method, or constructor invocation.
+ * Note that a method invocation also triggers a {@link MyAnalysis#getFieldPre} and a
+ * {@link MyAnalysis#getField} callbacks.
+ *
+ * @example
+ * y.f(a, b, c)
+ *
+ * // the above call roughly gets instrumented as follows:
+ *
+ * var skip = false;
+ * var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true);
+ * if (aret) {
+ * f = aret.f;
+ * y = aret.y;
+ * args = aret.args;
+ * skip = aret.skip
+ * }
+ * if (!skip) {
+ * f.apply(y, args);
+ * }
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {function} f - The function object that going to be invoked
+ * @param {object} base - The receiver object for the function f
+ * @param {Array} args - The array of arguments passed to f
+ * @param {boolean} isConstructor - True if f is invoked as a constructor
+ * @param {boolean} isMethod - True if f is invoked as a method
+ * @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created
+ * @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created
+ * {@link MyAnalysis#functionEnter} when the function f is executed. The functionIid can be
+ * treated as the static identifier of the function f. Note that a given function code block can
+ * create several function objects, but each such object has a common functionIid, which is the iid
+ * that is passed to {@link MyAnalysis#functionEnter} when the function executes.
+ * @returns {{f: function, base: Object, args: Array, skip: boolean}|undefined} - If an object is returned and
+ * the skip property of the object is true, then the invocation operation is skipped.
+ * Original f, base, and args are replaced with that from the returned object if
+ * an object is returned.
+ *
+ */
+ this.invokeFunPre = function (iid, f, base, args, isConstructor, isMethod, functionIid, functionSid) {
+ return {f: f, base: base, args: args, skip: false};
+ };
+
+ /**
+ * This callback is called after a function, method, or constructor invocation.
+ *
+ * @example
+ * x = y.f(a, b, c)
+ *
+ * // the above call roughly gets instrumented as follows:
+ *
+ * var skip = false;
+ * var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true);
+ * if (aret) {
+ * f = aret.f;
+ * y = aret.y;
+ * args = aret.args;
+ * skip = aret.skip
+ * }
+ * if (!skip) {
+ * result =f.apply(y, args);
+ * }
+ * aret = analysis.invokeFun(117, f, y, args, result, false, true);
+ * if (aret) {
+ * x = aret.result
+ * } else {
+ * x = result;
+ * }
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {function} f - The function object that was invoked
+ * @param {*} base - The receiver object for the function f
+ * @param {Array} args - The array of arguments passed to f
+ * @param {*} result - The value returned by the invocation
+ * @param {boolean} isConstructor - True if f is invoked as a constructor
+ * @param {boolean} isMethod - True if f is invoked as a method
+ * @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created
+ * @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created
+ * {@link MyAnalysis#functionEnter} when the function f is executed. functionIid can be treated as the
+ * static identifier of the function f. Note that a given function code block can create several function
+ * objects, but each such object has a common functionIid, which is the iid that is passed to
+ * {@link MyAnalysis#functionEnter} when the function executes.
+ * @returns {{result: *}| undefined} - If an object is returned, the return value of the invoked function is
+ * replaced with the value stored in the result property of the object. This enables one to change the
+ * value that is returned by the actual function invocation.
+ *
+ */
+ this.invokeFun = function (iid, f, base, args, result, isConstructor, isMethod, functionIid, functionSid) {
+ return {result: result};
+ };
+
+ /**
+ * This callback is called after the creation of a literal. A literal can be a function literal, an object literal,
+ * an array literal, a number, a string, a boolean, a regular expression, null, NaN, Infinity, or undefined.
+ *
+ * @example
+ * x = "Hello"
+ *
+ * // the above call roughly gets instrumented as follows:
+ *
+ * var result = "Hello";
+ * var aret = analysis.literal(201, result, false);
+ * if (aret) {
+ * result = aret.result;
+ * }
+ * x = result;
+ *
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} val - The literal value
+ * @param {boolean} hasGetterSetter - True if the literal is an object and the object defines getters and setters
+ * @returns {{result: *} | undefined} - If the function returns an object, then the original literal value is
+ * replaced with the value stored in the result property of the object.
+ *
+ */
+ this.literal = function (iid, val, hasGetterSetter) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called when a for-in loop is used to iterate the properties of an object.
+ *
+ *@example
+ * for (x in y) { }
+ *
+ * // the above call roughly gets instrumented as follows:
+ *
+ * var aret = analysis.forinObject(iid, y);
+ * if (aret) {
+ * y = aret.result;
+ * }
+ * for (x in y) {}
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} val - Objects whose properties are iterated in a for-in loop.
+ * @returns {{result: *} | undefined} - If the function returns an object, then the original object whose
+ * properties are being iterated is replaced with the value stored in the result property of the
+ * returned object.
+ *
+ */
+ this.forinObject = function (iid, val) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is triggered at the beginning of a scope for every local variable declared in the scope, for
+ * every formal parameter, for every function defined using a function statement, for arguments
+ * variable, and for the formal parameter passed in a catch statement.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} name - Name of the variable that is declared
+ * @param {*} val - Initial value of the variable that is declared. Variables can be local variables, function
+ * parameters, catch parameters, arguments, or functions defined using function statements. Variables
+ * declared with var have undefined as initial values and cannot be changed by returning a
+ * different value from this callback. On the beginning of an execution of a function, a declare
+ * callback is called on the arguments variable.
+ * @param {boolean} isArgument - True if the variable is arguments or a formal parameter.
+ * @param {number} argumentIndex - Index of the argument in the function call. Indices start from 0. If the
+ * variable is not a formal parameter, then argumentIndex is -1.
+ * @param {boolean} isCatchParam - True if the variable is a parameter of a catch statement.
+ * @returns {{result: *} | undefined} - If the function returns an object, then the original initial value is
+ * replaced with the value stored in the result property of the object. This does not apply to local
+ * variables declared with var.
+ *
+ */
+ this.declare = function (iid, name, val, isArgument, argumentIndex, isCatchParam) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called before a property of an object is accessed.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} base - Base object
+ * @param {string|*} offset - Property
+ * @param {boolean} isComputed - True if property is accessed using square brackets. For example,
+ * isComputed is true if the get field operation is o[p], and false
+ * if the get field operation is o.p
+ * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e
+ * @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. o.p())
+ * @returns {{base: *, offset: *, skip: boolean} | undefined} - If an object is returned and the skip
+ * property of the object is true, then the get field operation is skipped. Original base and
+ * offset are replaced with that from the returned object if an object is returned.
+ *
+ */
+ this.getFieldPre = function (iid, base, offset, isComputed, isOpAssign, isMethodCall) {
+ return {base: base, offset: offset, skip: false};
+ };
+
+ /**
+ * This callback is called after a property of an object is accessed.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} base - Base object
+ * @param {string|*} offset - Property
+ * @param {*} val - Value of base[offset]
+ * @param {boolean} isComputed - True if property is accessed using square brackets. For example,
+ * isComputed is true if the get field operation is o[p], and false
+ * if the get field operation is o.p
+ * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e
+ * @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. o.p())
+ * @returns {{result: *} | undefined} - If an object is returned, the value of the get field operation is
+ * replaced with the value stored in the result property of the object.
+ */
+ this.getField = function (iid, base, offset, val, isComputed, isOpAssign, isMethodCall) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called before a property of an object is written.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} base - Base object
+ * @param {*} offset - Property
+ * @param {*} val - Value to be stored in base[offset]
+ * @param {boolean} isComputed - True if property is accessed using square brackets. For example,
+ * isComputed is true if the get field operation is o[p], and false
+ * if the get field operation is o.p
+ * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e
+ * @returns {{base: *, offset: *, val: *, skip: boolean} | undefined} - If an object is returned and the skip
+ * property is true, then the put field operation is skipped. Original base, offset, and
+ * val are replaced with that from the returned object if an object is returned.
+ */
+ this.putFieldPre = function (iid, base, offset, val, isComputed, isOpAssign) {
+ return {base: base, offset: offset, val: val, skip: false};
+ };
+
+ /**
+ * This callback is called after a property of an object is written.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} base - Base object
+ * @param {*} offset - Property
+ * @param {*} val - Value to be stored in base[offset]
+ * @param {boolean} isComputed - True if property is accessed using square brackets. For example,
+ * isComputed is true if the get field operation is o[p], and false
+ * if the get field operation is o.p
+ * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e
+ * @returns {{result: *} | undefined} - If an object is returned, the result of the put field operation is
+ * replaced with the value stored in the result property of the object.
+ */
+ this.putField = function (iid, base, offset, val, isComputed, isOpAssign) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called after a variable is read.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} name - Name of the variable being read
+ * @param {*} val - Value read from the variable
+ * @param {boolean} isGlobal - True if the variable is not declared using var (e.g. console)
+ * @param {boolean} isScriptLocal - True if the variable is declared in the global scope using var
+ * @returns {{result: *} | undefined} - If an object is returned, the result of the read operation is
+ * replaced with the value stored in the result property of the object.
+ */
+ this.read = function (iid, name, val, isGlobal, isScriptLocal) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called before a variable is written.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} name - Name of the variable being read
+ * @param {*} val - Value to be written to the variable
+ * @param {*} lhs - Value stored in the variable before the write operation
+ * @param {boolean} isGlobal - True if the variable is not declared using var (e.g. console)
+ * @param {boolean} isScriptLocal - True if the variable is declared in the global scope using var
+ * @returns {{result: *} | undefined} - If an object is returned, the result of the write operation is
+ * replaced with the value stored in the result property of the object.
+ */
+ this.write = function (iid, name, val, lhs, isGlobal, isScriptLocal) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called before a value is returned from a function using the return keyword.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} val - Value to be returned
+ * @returns {{result: *} | undefined} - If an object is returned, the value to be returned is
+ * replaced with the value stored in the result property of the object.
+ */
+ this._return = function (iid, val) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called before a value is thrown using the throw keyword.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} val - Value to be thrown
+ * @returns {{result: *} | undefined} - If an object is returned, the value to be thrown is
+ * replaced with the value stored in the result property of the object.
+ */
+ this._throw = function (iid, val) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called when a with statement is executed
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} val - Value used as an argument to with
+ * @returns {{result: *} | undefined} - If an object is returned, the value to be used in with is
+ * replaced with the value stored in the result property of the object.
+ */
+ this._with = function (iid, val) {
+ return {result: val};
+ };
+
+ /**
+ * This callback is called before the execution of a function body starts.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {function} f - The function object whose body is about to get executed
+ * @param {*} dis - The value of the this variable in the function body
+ * @param {Array} args - List of the arguments with which the function is called
+ * @returns {undefined} - Any return value is ignored
+ */
+ this.functionEnter = function (iid, f, dis, args) {
+ };
+
+ /**
+ * This callback is called when the execution of a function body completes
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} returnVal - The value returned by the function
+ * @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the function
+ * execution has thrown an uncaught exception and the exception is being stored in the exception
+ * property of the parameter
+ * @returns {{returnVal: *, wrappedExceptionVal: *, isBacktrack: boolean}} If an object is returned, then the
+ * actual returnVal and wrappedExceptionVal.exception are replaced with that from the
+ * returned object. If an object is returned and the property isBacktrack is set, then the control-flow
+ * returns to the beginning of the function body instead of returning to the caller. The property
+ * isBacktrack can be set to true to repeatedly execute the function body as in MultiSE
+ * symbolic execution.
+ */
+ this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
+ return {returnVal: returnVal, wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false};
+ };
+
+ /**
+ * This callback is called before the execution of a JavaScript file
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} instrumentedFileName - Name of the instrumented script file
+ * @param {string} originalFileName - Name of the original script file
+ */
+ this.scriptEnter = function (iid, instrumentedFileName, originalFileName) {
+ };
+
+ /**
+ * This callback is called when the execution of a JavaScript file completes
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the script
+ * execution has thrown an uncaught exception and the exception is being stored in the exception
+ * property of the parameter
+ * @returns {{wrappedExceptionVal: *, isBacktrack: boolean}} - If an object is returned, then the
+ * actual wrappedExceptionVal.exception is replaced with that from the
+ * returned object. If an object is returned and the property isBacktrack is set, then the control-flow
+ * returns to the beginning of the script body. The property
+ * isBacktrack can be set to true to repeatedly execute the script body as in MultiSE
+ * symbolic execution.
+ */
+ this.scriptExit = function (iid, wrappedExceptionVal) {
+ return {wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false};
+ };
+
+ /**
+ * This callback is called before a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
+ * <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in. No callback for delete x
+ * because this operation cannot be performed reflectively.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} op - Operation to be performed
+ * @param {*} left - Left operand
+ * @param {*} right - Right operand
+ * @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form
+ * x op= e
+ * @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant
+ * with a consequent in a switch statement.
+ * @param {boolean} isComputed - True if the operation is of the form delete x[p], and false
+ * otherwise (even if the operation if of the form delete x.p)
+ * @returns {{op: string, left: *, right: *, skip: boolean}|undefined} - If an object is returned and the
+ * skip property is true, then the binary operation is skipped. Original op, left,
+ * and right are replaced with that from the returned object if an object is returned.
+ */
+ this.binaryPre = function (iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed) {
+ return {op: op, left: left, right: right, skip: false};
+ };
+
+ /**
+ * This callback is called after a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
+ * <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} op - Operation to be performed
+ * @param {*} left - Left operand
+ * @param {*} right - Right operand
+ * @param {*} result - The result of the binary operation
+ * @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form
+ * x op= e
+ * @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant
+ * with a consequent in a switch statement.
+ * @param {boolean} isComputed - True if the operation is of the form delete x[p], and false
+ * otherwise (even if the operation if of the form delete x.p)
+ * @returns {{result: *}|undefined} - If an object is returned, the result of the binary operation is
+ * replaced with the value stored in the result property of the object.
+ */
+ this.binary = function (iid, op, left, right, result, isOpAssign, isSwitchCaseComparison, isComputed) {
+ return {result: result};
+ };
+
+ /**
+ * This callback is called before a unary operation. Unary operations include +, -, ~, !, typeof, void.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} op - Operation to be performed
+ * @param {*} left - Left operand
+ * @returns {{op: *, left: *, skip: boolean} | undefined} If an object is returned and the
+ * skip property is true, then the unary operation is skipped. Original op and left
+ * are replaced with that from the returned object if an object is returned.
+ */
+ this.unaryPre = function (iid, op, left) {
+ return {op: op, left: left, skip: false};
+ };
+
+ /**
+ * This callback is called after a unary operation. Unary operations include +, -, ~, !, typeof, void.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {string} op - Operation to be performed
+ * @param {*} left - Left operand
+ * @param {*} result - The result of the unary operation
+ * @returns {{result: *}|undefined} - If an object is returned, the result of the unary operation is
+ * replaced with the value stored in the result property of the object.
+ *
+ */
+ this.unary = function (iid, op, left, result) {
+ return {result: result};
+ };
+
+ /**
+ * This callback is called after a condition check before branching. Branching can happen in various statements
+ * including if-then-else, switch-case, while, for, ||, &&, ?:.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} result - The value of the conditional expression
+ * @returns {{result: *}|undefined} - If an object is returned, the result of the conditional expression is
+ * replaced with the value stored in the result property of the object.
+ */
+ this.conditional = function (iid, result) {
+ return {result: result};
+ };
+
+ /**
+ * This callback is called before a string passed as an argument to eval or Function is instrumented.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} code - Code that is going to get instrumented
+ * @param {boolean} isDirect - true if this is a direct call to eval
+ * @returns {{code: *, skip: boolean}} - If an object is returned and the
+ * skip property is true, then the instrumentation of code is skipped.
+ * Original code is replaced with that from the returned object if an object is returned.
+ */
+ this.instrumentCodePre = function (iid, code, isDirect) {
+ return {code: code, skip: false};
+ };
+
+ /**
+ * This callback is called after a string passed as an argument to eval or Function is instrumented.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {*} newCode - Instrumented code
+ * @param {Object} newAst - The AST of the instrumented code
+ * @param {boolean} isDirect - true if this is a direct call to eval
+ * @returns {{result: *}|undefined} - If an object is returned, the instrumented code is
+ * replaced with the value stored in the result property of the object.
+ */
+ this.instrumentCode = function (iid, newCode, newAst, isDirect) {
+ return {result: newCode};
+ };
+
+ /**
+ * This callback is called when an expression is evaluated and its value is discarded. For example, this
+ * callback is called when an expression statement completes its execution.
+ *
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @returns {undefined} - Any return value is ignored
+ */
+ this.endExpression = function (iid) {
+ };
+
+ /**
+ * This callback is called when an execution terminates in node.js. In a browser environment, the callback is
+ * called if ChainedAnalyses.js or ChainedAnalysesNoCheck.js is used and Alt-Shift-T is pressed.
+ *
+ * @returns {undefined} - Any return value is ignored
+ */
+ this.endExecution = function () {
+ };
+
+ /**
+ * This callback is called only when instrumented with J$.Config.ENABLE_SAMPLING = true
+ * This callback is called before the body of a function, method, or constructor is executed
+ * if returns true, instrumented function body is executed, else uninstrumented function body is executed
+ * @param {number} iid - Static unique instruction identifier of this callback
+ * @param {function} f - The function whose body is being executed
+ * @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created
+ * @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created
+ * {@link MyAnalysis#functionEnter} when the function f is executed. The functionIid can be
+ * treated as the static identifier of the function f. Note that a given function code block can
+ * create several function objects, but each such object has a common functionIid, which is the iid
+ * that is passed to {@link MyAnalysis#functionEnter} when the function executes.
+ * @returns {boolean} - If true is returned the instrumented function body is executed, otherwise the
+ * uninstrumented function body is executed.
+ */
+ this.runInstrumentedFunctionBody = function (iid, f, functionIid, functionSid) {
+ return false;
+ };
+
+ /**
+ * onReady is useful if your analysis is running on node.js (i.e., via the direct.js or jalangi.js commands)
+ * and needs to complete some asynchronous initialization before the instrumented program starts. In such a
+ * case, once the initialization is complete, invoke the cb function to start execution of the instrumented
+ * program.
+ *
+ * Note that this callback is not useful in the browser, as Jalangi has no control over when the
+ * instrumented program runs there.
+ * @param cb
+ */
+ this.onReady = function (cb) {
+ cb();
+ };
+ }
+
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
diff --git a/jalangi2/src/js/runtime/iidToLocation.js b/jalangi2/src/js/runtime/iidToLocation.js
new file mode 100644
index 00000000000..e1ae35c23fb
--- /dev/null
+++ b/jalangi2/src/js/runtime/iidToLocation.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013-2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+if (typeof J$ === 'undefined') {
+ J$ = {};
+}
+
+(function (sandbox) {
+ if (typeof sandbox.iidToLocation !== 'undefined') {
+ return;
+ }
+ sandbox.iidToLocation = function (sid, iid) {
+ var ret, arr, gid=sid;
+ if (sandbox.smap) {
+ if (typeof sid === 'string' && sid.indexOf(':')>=0) {
+ sid = sid.split(':');
+ iid = parseInt(sid[1]);
+ sid = parseInt(sid[0]);
+ } else {
+ gid = sid+":"+iid;
+ }
+ if ((ret = sandbox.smap[sid])) {
+ var fname = ret.originalCodeFileName;
+ if (ret.evalSid !== undefined) {
+ fname = fname+sandbox.iidToLocation(ret.evalSid, ret.evalIid);
+ }
+ arr = ret[iid];
+ if (arr) {
+ if (sandbox.Results) {
+ return "(" + fname + ":" + arr[0] + ":" + arr[1] + ":" + arr[2] + ":" + arr[3] + ")";
+ } else {
+ return "(" + fname + ":" + arr[0] + ":" + arr[1] + ":" + arr[2] + ":" + arr[3] + ")";
+ }
+ } else {
+ return "(" + fname + ":iid" + iid + ")";
+ }
+ }
+ }
+ return sid+"";
+ };
+
+ sandbox.getGlobalIID = function(iid) {
+ return sandbox.sid +":"+iid;
+ }
+
+}(J$));
diff --git a/jalangi2/src/js/sample_analyses/ChainedAnalyses.js b/jalangi2/src/js/sample_analyses/ChainedAnalyses.js
new file mode 100644
index 00000000000..2470af0a673
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/ChainedAnalyses.js
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+(function (sandbox) {
+ function ChainedAnalyses() {
+
+ function clientAnalysisException(e) {
+ console.error("analysis exception!!!");
+ console.error(e.stack);
+ if (typeof process !== 'undefined' && process.exit) {
+ process.exit(1);
+ } else {
+ throw e;
+ }
+ }
+
+ var funList = ["_return", "_throw", "_with",
+ "binaryPre", "binary", "conditional",
+ "declare", "endExecution", "endExpression",
+ "forinObject", "functionEnter", "functionExit",
+ "getFieldPre", "getField", "instrumentCodePre",
+ "instrumentCode", "invokeFunPre", "invokeFun",
+ "literal", "onReady","putFieldPre",
+ "putField", "read", "runInstrumentedFunctionBody",
+ "scriptEnter", "scriptExit", "unaryPre",
+ "unary", "write"];
+
+ this.globals = {};
+
+ this.addAnalysis = function (analysis) {
+ var self = this, tmp, length = funList.length;
+
+ for (var i = 0; i < length; i++) {
+ var field = funList[i];
+ if (tmp = analysis[field]) {
+ var fun = self[field];
+ if (!fun) {
+ fun = self[field] = function () {
+ try {
+ var ret1;
+ var thisFun = arguments.callee;
+ var len = thisFun.afs.length;
+ var args = [];
+ for(var x=0;x= 0) {
+ return str;
+ }
+ str = str + "";
+ if (HOP(stringMap,str)) {
+ return stringMap[str];
+ } else {
+ stringCount++;
+ stringMap[str] = stringCount;
+ stringList.push(str);
+ return -stringCount;
+ }
+ }
+
+
+ this.invokeFunPre = function (iid, f, base, args, isConstructor, isMethod, functionIid) {
+ lastiid = iid;
+ lastsid = sandbox.sid;
+ };
+
+
+ this.getFieldPre = function (iid, base, offset, isComputed, isOpAssign, isMethodCall) {
+ lastiid = iid;
+ lastsid = sandbox.sid;
+ };
+
+ this.getField = function (iid, base, offset, val, isComputed, isOpAssign, isMethodCall) {
+ var so = sandbox.smemory.getShadowObjectOfObject(base);
+ var objectId = so?sandbox.smemory.getIDFromShadowObjectOrFrame(so):0;
+ var shadowObj = sandbox.smemory.getShadowObject(base, offset, true);
+ var ownerId = shadowObj.owner ? sandbox.smemory.getIDFromShadowObjectOrFrame(shadowObj.owner) : 0;
+ if (shadowObj.isProperty) {
+ logEvent('G,' + sandbox.sid + "," + iid + "," + objectId + "," + ownerId + "," + getStringIndex(offset) + "," + getValue(val) + "," + getType(val));
+ }
+ };
+
+ this.putFieldPre = function (iid, base, offset, val, isComputed, isOpAssign) {
+ lastiid = iid;
+ lastsid = sandbox.sid;
+ var objectId = sandbox.smemory.getIDFromShadowObjectOrFrame(sandbox.smemory.getShadowObjectOfObject(base));
+ var shadowObj = sandbox.smemory.getShadowObject(base, offset, false);
+ var ownerId = shadowObj.owner ? sandbox.smemory.getIDFromShadowObjectOrFrame(shadowObj.owner) : 0;
+ if (shadowObj.isProperty) {
+ logEvent('P,' + sandbox.sid + "," + iid + "," + objectId + "," + ownerId + "," + getStringIndex(offset) + "," + getValue(val) + "," + getType(val));
+ }
+ };
+
+ this.read = function (iid, name, val, isGlobal, isScriptLocal) {
+ var shadowFrame = sandbox.smemory.getShadowFrame(name);
+ logEvent('R,' + sandbox.sid + "," + iid + "," + sandbox.smemory.getIDFromShadowObjectOrFrame(shadowFrame) + "," + getStringIndex(name) + "," + getValue(val) + "," + getType(val));
+ };
+
+ this.write = function (iid, name, val, lhs, isGlobal, isScriptLocal) {
+ var shadowFrame = sandbox.smemory.getShadowFrame(name);
+ logEvent('W,' + sandbox.sid + "," + iid + "," + sandbox.smemory.getIDFromShadowObjectOrFrame(shadowFrame) + "," + getStringIndex(name) + "," + getValue(val) + "," + getType(val));
+ };
+
+ this.functionEnter = function (iid, f, dis, args) {
+ var shadowFrame = sandbox.smemory.getShadowFrame('this');
+ logEvent('C,'+lastsid+","+lastiid+","+getValue(f)+","+sandbox.smemory.getIDFromShadowObjectOrFrame(shadowFrame));
+ };
+
+ this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
+ logEvent('E,' + sandbox.sid + "," + iid + "," + getValue(returnVal) + "," + getType(returnVal));
+ };
+
+ this.endExecution = function () {
+ traceWriter.stopTracing();
+ var tw = new sandbox.TraceWriter("strings.json");
+ tw.logToFile(JSON.stringify(stringList)+"\n");
+ tw.stopTracing();
+ tw = new sandbox.TraceWriter("smap.json");
+ tw.logToFile(JSON.stringify(sandbox.smap)+"\n");
+ tw.stopTracing();
+ };
+
+ this.runInstrumentedFunctionBody = function (iid, f, functionIid) {
+ return false;
+ };
+
+ /**
+ * onReady is useful if your analysis is running on node.js (i.e., via the direct.js or jalangi.js commands)
+ * and needs to complete some asynchronous initialization before the instrumented program starts. In such a
+ * case, once the initialization is complete, invoke the cb function to start execution of the instrumented
+ * program.
+ *
+ * Note that this callback is not useful in the browser, as Jalangi has no control over when the
+ * instrumented program runs there.
+ * @param cb
+ */
+ this.onReady = function (cb) {
+ cb();
+ };
+ }
+
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+// node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/ChainedAnalyses.js --analysis src/js/runtime/SMemory.js --analysis src/js/sample_analyses/datatraces/TraceWriter.js --analysis src/js/sample_analyses/datatraces/LogData.js tests/octane/deltablue.js
+
diff --git a/jalangi2/src/js/sample_analyses/datatraces/TraceWriter.js b/jalangi2/src/js/sample_analyses/datatraces/TraceWriter.js
new file mode 100644
index 00000000000..6f8acf026bc
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/datatraces/TraceWriter.js
@@ -0,0 +1,135 @@
+(function (sandbox) {
+
+
+ sandbox.TraceWriter = function (traceFileName) {
+ var Constants = sandbox.Constants;
+ var Config = sandbox.Config;
+
+ var bufferSize = 0;
+ var buffer = [];
+ var traceWfh;
+ var fs = (!Constants.isBrowser) ? require('fs') : undefined;
+ var trying = false;
+ var cb;
+ var remoteBuffer = [];
+ var socket, isOpen = false;
+ // if true, in the process of doing final trace dump,
+ // so don't record any more events
+ var tracingDone = false;
+
+ function getFileHanlde() {
+ if (traceWfh === undefined) {
+ traceWfh = fs.openSync(traceFileName, 'w');
+ }
+ return traceWfh;
+ }
+
+ /**
+ * @param {string} line
+ */
+ this.logToFile = function (line) {
+ if (tracingDone) {
+ // do nothing
+ return;
+ }
+ var len = line.length;
+ // we need this loop because it's possible that len >= Config.MAX_BUF_SIZE
+ // TODO fast path for case where len < Config.MAX_BUF_SIZE?
+ var start = 0, end = len < Config.MAX_BUF_SIZE ? len : Config.MAX_BUF_SIZE;
+ while (start < len) {
+ var chunk = line.substring(start, end);
+ var curLen = end - start;
+ if (bufferSize + curLen > Config.MAX_BUF_SIZE) {
+ this.flush();
+ }
+ buffer.push(chunk);
+ bufferSize += curLen;
+ start = end;
+ end = (end + Config.MAX_BUF_SIZE < len) ? end + Config.MAX_BUF_SIZE : len;
+ }
+ };
+
+ this.flush = function () {
+ var msg;
+ if (!Constants.isBrowser) {
+ var length = buffer.length;
+ for (var i = 0; i < length; i++) {
+ fs.writeSync(getFileHanlde(), buffer[i]);
+ }
+ } else {
+ msg = buffer.join('');
+ if (msg.length > 1) {
+ this.remoteLog(msg);
+ }
+ }
+ bufferSize = 0;
+ buffer = [];
+ };
+
+
+ function openSocketIfNotOpen() {
+ if (!socket) {
+ console.log("Opening connection");
+ socket = new WebSocket('ws://127.0.0.1:8080', 'log-protocol');
+ socket.onopen = tryRemoteLog;
+ socket.onmessage = tryRemoteLog2;
+ }
+ }
+
+ /**
+ * invoked when we receive a message over the websocket,
+ * indicating that the last trace chunk in the remoteBuffer
+ * has been received
+ */
+ function tryRemoteLog2() {
+ trying = false;
+ remoteBuffer.shift();
+ if (remoteBuffer.length === 0) {
+ if (cb) {
+ cb();
+ cb = undefined;
+ }
+ }
+ tryRemoteLog();
+ }
+
+ this.onflush = function (callback) {
+ if (remoteBuffer.length === 0) {
+ if (callback) {
+ callback();
+ }
+ } else {
+ cb = callback;
+ tryRemoteLog();
+ }
+ };
+
+ function tryRemoteLog() {
+ isOpen = true;
+ if (!trying && remoteBuffer.length > 0) {
+ trying = true;
+ socket.send(remoteBuffer[0]);
+ }
+ }
+
+ this.remoteLog = function (message) {
+ if (message.length > Config.MAX_BUF_SIZE) {
+ throw new Error("message too big!!!");
+ }
+ remoteBuffer.push(message);
+ openSocketIfNotOpen();
+ if (isOpen) {
+ tryRemoteLog();
+ }
+ };
+
+ /**
+ * stop recording the trace and flush everything
+ */
+ this.stopTracing = function () {
+ tracingDone = true;
+ this.flush();
+ };
+ }
+
+})(J$);
diff --git a/jalangi2/src/js/sample_analyses/dlint/CheckNaN.js b/jalangi2/src/js/sample_analyses/dlint/CheckNaN.js
new file mode 100644
index 00000000000..29b64362439
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dlint/CheckNaN.js
@@ -0,0 +1,68 @@
+
+
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+
+(function (sandbox) {
+ function MyAnalysis () {
+ var iidToLocation = sandbox.iidToLocation;
+ var Constants = sandbox.Constants;
+ var HOP = Constants.HOP;
+ var sort = Array.prototype.sort;
+
+ var info = {};
+
+ this.invokeFun = function(iid, f, base, args, result, isConstructor, isMethod){
+ if (result !== result) {
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ }
+ };
+
+ this.getField = function(iid, base, offset, val){
+ if (val !== val) {
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ }
+ };
+
+ this.binary = function(iid, op, left, right, result){
+ if (result !== result) {
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ }
+ };
+
+ this.unary = function(iid, op, left, result){
+ if (result !== result) {
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ }
+ };
+
+ this.endExecution = function() {
+ sandbox.Utils.printInfo(info, function(x) {
+ sandbox.log("Observed NaN at "+iidToLocation(x.iid)+" "+ x.count+" time(s).");
+ });
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/dlint/CompareFunctionWithPrimitives.js b/jalangi2/src/js/sample_analyses/dlint/CompareFunctionWithPrimitives.js
new file mode 100644
index 00000000000..3e5338bce03
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dlint/CompareFunctionWithPrimitives.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+// probably forgot to call a function before comparison
+(function (sandbox) {
+ function MyAnalysis () {
+ var iidToLocation = sandbox.iidToLocation;
+
+ var info = {};
+
+ this.binary = function(iid, op, left, right, result){
+ var type1 = typeof left;
+ var type2 = typeof right;
+ if (op === '==' ||
+ op === '===' ||
+ op === '!==' ||
+ op === '!=' ||
+ op === '<' ||
+ op === '>' ||
+ op === '<=' ||
+ op === '>='){
+ if ((type1 === 'function' && (type2 ==='string' || type2 ==='number' || type2==='boolean')) ||
+ (type2 === 'function' && (type1 ==='string' || type1 ==='number' || type1==='boolean'))) {
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)] | 0) + 1;
+ }
+ }
+ };
+
+ this.endExecution = function() {
+ sandbox.Utils.printInfo(info, function(x){
+ sandbox.log("Comparing a function with a number or string or boolean at "+iidToLocation(x.iid)+" "+ x.count+" time(s).");
+
+ });
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/dlint/ConcatUndefinedToString.js b/jalangi2/src/js/sample_analyses/dlint/ConcatUndefinedToString.js
new file mode 100644
index 00000000000..a2e34642c71
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dlint/ConcatUndefinedToString.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+
+(function (sandbox) {
+ function MyAnalysis () {
+ var iidToLocation = sandbox.iidToLocation;
+ var Constants = sandbox.Constants;
+ var HOP = Constants.HOP;
+ var sort = Array.prototype.sort;
+
+ var info = {};
+
+ this.binary = function(iid, op, left, right, result){
+ if (op === '+' && typeof result==='string' && (left===undefined || right===undefined)) {
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ }
+ };
+
+ this.endExecution = function() {
+ sandbox.Utils.printInfo(info, function(x){
+ sandbox.log("Concatenated undefined to a string at "+iidToLocation(x.iid)+" "+ x.count+" time(s).");
+
+ });
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/dlint/FunCalledWithMoreArguments.js b/jalangi2/src/js/sample_analyses/dlint/FunCalledWithMoreArguments.js
new file mode 100644
index 00000000000..4a4d9e1568a
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dlint/FunCalledWithMoreArguments.js
@@ -0,0 +1,67 @@
+
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+// In the following callbacks one can choose to not return anything.
+// If all of the callbacks return nothing, we get a passive analysis where the
+// concrete execution happens unmodified and callbacks are used to observe the execution.
+// Once can choose to return suitable objects with specified fields in some callbacks
+// to modify the behavior of the concrete execution. For example, one could set the skip
+// field of an object returned from putFieldPre to true to skip the actual putField operation.
+// Similarly, one could set the result field of the object returned from a write callback
+// to modify the value that is actually written to a variable. The result field of the object
+// returned from a conditional callback can be suitably set to change the control-flow of the
+// program execution. In functionExit and scriptExit,
+// one can set the isBacktrack field of the returned object to true to reexecute the body of
+// the function from the beginning. This in conjunction with the ability to change the
+// control-flow of a program enables us to explore the different paths of a function in
+// symbolic execution.
+
+(function (sandbox) {
+ function MyAnalysis () {
+ var iidToLocation = sandbox.iidToLocation;
+
+ function isNative(f) {
+ return f.toString().indexOf('[native code]') > -1 || f.toString().indexOf('[object ') === 0;
+ }
+
+
+ var info = {};
+
+ this.invokeFunPre = function(iid, f, base, args, isConstructor, isMethod){
+ if (f.length < args.length && !isNative(f)) {
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ }
+ };
+
+
+ this.endExecution = function() {
+ sandbox.Utils.printInfo(info, function(x) {
+ sandbox.log("Function at "+iidToLocation(x.iid)+" called "+ x.count+" time(s) with more arguments that expected.");
+
+ });
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/dlint/ShadowProtoProperty.js b/jalangi2/src/js/sample_analyses/dlint/ShadowProtoProperty.js
new file mode 100644
index 00000000000..431537e995b
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dlint/ShadowProtoProperty.js
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+
+// In the following callbacks one can choose to not return anything.
+// If all of the callbacks return nothing, we get a passive analysis where the
+// concrete execution happens unmodified and callbacks are used to observe the execution.
+// Once can choose to return suitable objects with specified fields in some callbacks
+// to modify the behavior of the concrete execution. For example, one could set the skip
+// field of an object returned from putFieldPre to true to skip the actual putField operation.
+// Similarly, one could set the result field of the object returned from a write callback
+// to modify the value that is actually written to a variable. The result field of the object
+// returned from a conditional callback can be suitably set to change the control-flow of the
+// program execution. In functionExit and scriptExit,
+// one can set the isBacktrack field of the returned object to true to reexecute the body of
+// the function from the beginning. This in conjunction with the ability to change the
+// control-flow of a program enables us to explore the different paths of a function in
+// symbolic execution.
+
+(function (sandbox) {
+ function MyAnalysis () {
+ var iidToLocation = sandbox.iidToLocation;
+ var Constants = sandbox.Constants;
+ var HOP = Constants.HOP;
+ var sort = Array.prototype.sort;
+ var info = {};
+
+
+ this.putFieldPre = function(iid, base, offset, val){
+ if (typeof val !== 'function' && base && !HOP(base, offset)) {
+ var tmp = base.__proto__;
+ while(tmp) {
+ if (HOP(tmp, offset)) {
+ if (!info[sandbox.getGlobalIID(iid)]) {
+ info[sandbox.getGlobalIID(iid)] = {};
+ }
+ info[sandbox.getGlobalIID(iid)][offset] = (info[sandbox.getGlobalIID(iid)][offset]|0) + 1;
+ return;
+ }
+ tmp = tmp.__proto__;
+ }
+ }
+ };
+
+ this.endExecution = function() {
+ var tmp = [];
+ for (var iid in info) {
+ if (HOP(info, iid)) {
+ var offsets = info[iid];
+ for (var offset in offsets) {
+ if (HOP(offsets, offset)) {
+ tmp.push({iid:iid, offset:offset, count:offsets[offset]});
+ }
+ }
+ }
+ }
+ sort.call(tmp, function(a,b) {
+ return b.count - a.count;
+ });
+ for (var x in tmp) {
+ if (HOP(tmp, x)) {
+ x = tmp[x];
+ sandbox.log("Written property "+ x.offset+" at "+iidToLocation(x.iid)+" "+ x.count+" time(s) and it shadows the property in its prototype.");
+
+ }
+ }
+
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/dlint/UndefinedOffset.js b/jalangi2/src/js/sample_analyses/dlint/UndefinedOffset.js
new file mode 100644
index 00000000000..99578d0a405
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dlint/UndefinedOffset.js
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+
+(function (sandbox) {
+
+ function MyAnalysis () {
+ var iidToLocation = sandbox.iidToLocation;
+
+ var info = {};
+
+ this.getFieldPre = function(iid, base, offset){
+ if (offset === undefined)
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ };
+
+ this.putFieldPre = function(iid, base, offset, val){
+ if (offset === undefined)
+ info[sandbox.getGlobalIID(iid)] = (info[sandbox.getGlobalIID(iid)]|0) + 1;
+ };
+
+
+ this.endExecution = function() {
+ sandbox.Utils.printInfo(info, function(x) {
+ sandbox.log("Accessed property 'undefined' at "+iidToLocation(x.iid)+" "+ x.count+" time(s).");
+
+ });
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/dlint/Utils.js b/jalangi2/src/js/sample_analyses/dlint/Utils.js
new file mode 100644
index 00000000000..11b6ed96580
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dlint/Utils.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+(function (sandbox) {
+ function Utils () {
+ var Constants = sandbox.Constants;
+ var HOP = Constants.HOP;
+ var sort = Array.prototype.sort;
+
+ this.printInfo = function(info, f) {
+ var tmp = [];
+ for (var iid in info) {
+ if (HOP(info, iid)) {
+ tmp.push({iid:iid, count:info[iid]});
+ }
+ }
+ sort.call(tmp, function(a,b) {
+ return b.count - a.count;
+ });
+ for (var x in tmp) {
+ if (HOP(tmp, x)) {
+ x = tmp[x];
+ f(x);
+ }
+ }
+ };
+ }
+ sandbox.Utils = new Utils();
+})(J$);
+
diff --git a/jalangi2/src/js/sample_analyses/dsjs/Dsjs.js b/jalangi2/src/js/sample_analyses/dsjs/Dsjs.js
new file mode 100644
index 00000000000..2349b656680
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dsjs/Dsjs.js
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+// run the following in the JALANGI_HOME directory
+// python scripts/dsjs.py tests/octane/richards; open jalangi_tmp/index.html
+
+(function (sandbox) {
+ var Constants = sandbox.Constants;
+ var iidToLocation = sandbox.iidToLocation;
+
+ var SPECIAL_PROP = Constants.SPECIAL_PROP + "M";
+ var objectId = 1;
+ var HOP = Constants.HOP;
+ var hasGetterSetter = Constants.hasGetterSetter;
+ var scriptName;
+
+ function isArr(obj) {
+ return Array.isArray(obj) || (obj && obj.constructor && (obj instanceof Uint8Array || obj instanceof Uint16Array ||
+ obj instanceof Uint32Array || obj instanceof Uint8ClampedArray ||
+ obj instanceof ArrayBuffer || obj instanceof Int8Array || obj instanceof Int16Array ||
+ obj instanceof Int32Array || obj instanceof Float32Array || obj instanceof Float64Array));
+ }
+
+ function isNormalNumber(num) {
+ if (typeof num === 'number' && !isNaN(num)) {
+ return true;
+ } else if (typeof num === 'string' && (this.parseInt(num) + "" === num)) {
+ return true;
+ }
+ return false;
+ }
+
+ function createShadowObject(iid, val) {
+ var type = typeof val;
+ if ((type === 'object' || type === 'function') && val !== null && !HOP(val, SPECIAL_PROP)) {
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(val, SPECIAL_PROP, {
+ enumerable:false,
+ writable:true
+ });
+ }
+ try {
+ val[SPECIAL_PROP] = Object.create(null);
+ val[SPECIAL_PROP][SPECIAL_PROP] = objectId;
+ objectId = objectId + 2;
+ val[SPECIAL_PROP].iid = iid;
+ } catch (e) {
+ // cannot attach special field in some DOM Objects. So ignore them.
+ }
+ }
+
+ }
+
+ function getShadowObject(iid, val) {
+ var value;
+ createShadowObject(iid, val);
+ var type = typeof val;
+ if ((type === 'object' || type === 'function') && val !== null && HOP(val, SPECIAL_PROP)) {
+ value = val[SPECIAL_PROP];
+ } else {
+ value = undefined;
+ }
+ return value;
+ }
+
+ var info = {};
+
+ function incOld(hash, property) {
+ hash[property] = (hash[property]|0) + 1;
+ }
+
+ function inc(hash) {
+ var i, len = arguments.length, map = hash, info, key;
+ for (i = 1; i < len; i++) {
+ key = arguments[i];
+ if (!(info = map[key])) {
+ info = map[key] = {count: 0};
+ }
+ info.count++;
+ if (i < len - 1 && !HOP(info, "details")) {
+ info.details = {};
+ }
+ map = info.details;
+ }
+ }
+
+
+ function updateSObjArrayNonUniformity(iid, sobj, elem) {
+ if (!sobj.typeInitialized) {
+ sobj.type = typeof elem;
+ sobj.typeInitialized = true;
+ sobj.isUniform = true;
+ } else if (sobj.isUniform) {
+ sobj.isUniform = (sobj.type == (typeof elem));
+ if (!sobj.isUniform) {
+ inc(info, "# of instructions at which an array becomes nonuniform", "times allocated at IID:" + sobj.iid, "times get nonuniform at IID:" + iid);
+ }
+ }
+ }
+
+ function updateSObjObjectNonUniformity(iid, sobj, elem) {
+ if (sobj && sobj.isDynamic) {
+ if (!sobj.typeInitialized) {
+ sobj.type = typeof elem;
+ sobj.typeInitialized = true;
+ sobj.isUniform = true;
+ } else if (sobj.isUniform) {
+ sobj.isUniform = (sobj.type == (typeof elem));
+ if (!sobj.isUniform) {
+ inc(info, "# of instructions at which object hashes become nonuniform", "times allocated at IID:" + sobj.iid, "times get nonuniform at IID:" + iid);
+ }
+ }
+ }
+ }
+
+ function checkObjectUniformity(iid, sobj, obj, elem) {
+ if (!sobj.isDynamic) {
+ sobj.isDynamic = true;
+ inc(info, "# of instructions at which an object become an hashtable", "times allocated at IID:" + sobj.iid, "times become hash at IID:" + iid);
+ for (var p in obj) {
+ if (!hasGetterSetter(obj, p, true))
+ updateSObjObjectNonUniformity(iid, sobj, obj[p]);
+ }
+ }
+ if (sobj.isDynamic) {
+ updateSObjObjectNonUniformity(iid, sobj, elem);
+ }
+ }
+
+ function checkArrayUniformity(iid, val) {
+ if (isArr(val)) {
+ inc(info, "# of arrays allocated");
+ var sobj = getShadowObject(iid, val);
+ var i;
+ for (i=0; i= base.length) {
+ if (offset === base.length) {
+ inc(info, "# of instructions where an element is appended to an array", "times appended at IID:" + iid);
+ } else {
+ inc(info, "# of instructions where an out of bound (excluding array.length index) array element is written", "time written at IID:" + iid);
+ }
+ }
+ } else {
+ //console.log(offset);
+ inc(info, "# of instructions where a non-number property (excluding length) is written", "times written at IID:" + iid, "times written property named " + offset);
+ }
+ sobj = getShadowObject(iid, base);
+ updateSObjArrayNonUniformity(iid, sobj, val);
+ } else if (typeof base === "object") {
+ inc(info, "# of instructions where an object property is written");
+ if (!HOP(base, offset) && base !== currThis) {
+ sobj = getCreateObjectInfo(iid, base, false);
+ if (!sobj || !sobj.isPrototype) {
+ inc(info, "# of instructions where an object property is added outside a literal or constructor", "times added at IID:" + iid, "times added property named " + offset);
+ if (sobj) {
+ checkObjectUniformity(iid, sobj, base, val);
+ }
+ }
+ }
+ }
+ return {base: base, offset: offset, val: val, skip: false};
+ };
+
+ this.functionEnter = function (iid, f, dis, args) {
+ if (isCallingConstructor && f === constructorFun) {
+ currThis = dis;
+ } else {
+ currThis = undefined;
+ }
+ thisStack.push(currThis);
+ };
+
+ this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
+ thisStack.pop();
+ currThis = thisStack[thisStack.length - 1];
+ return {returnVal: returnVal, wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false};
+ };
+
+ this.scriptEnter = function (iid, val) {
+ if (!scriptName) {
+ scriptName = val;
+ }
+ };
+
+ function createTree(input, name, c) {
+ var output = {"name": name, "count": c}, tmp, children = [], idx;
+ if (input) {
+ for (var key in input) {
+ if (HOP(input, key)) {
+ tmp = input[key];
+ var count = tmp.count;
+ var child = tmp.details;
+ var txt;
+ if ((idx = key.indexOf("IID:")) >= 0) {
+ txt = key.substring(0, idx) + iidToLocation(key.substring(idx + 4));
+ } else {
+ txt = key
+ }
+ child = createTree(child, txt + " = " + count, count);
+ children.push(child);
+ }
+ }
+ }
+ children.sort(function (a, b) {
+ if (b.count > a.count)
+ return 1;
+ else if (b.count < a.count)
+ return -1;
+ else
+ return 0;
+
+ });
+ if (children.length > 0) {
+ output.children = children;
+ } else {
+ output.size = 2000;
+ }
+ return output;
+ }
+
+ this.endExecution = function() {
+// console.log(JSON.stringify(info, null, 4));
+ var fs = require('fs'), path = require('path');
+ var contents = fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf8');
+ fs.writeFileSync('index.html', contents, 'utf8');
+ fs.appendFileSync("index.html", "", "utf8");
+ //require('fs').writeFileSync("../info.json", JSON.stringify(info, null, 4), "utf8");
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
diff --git a/jalangi2/src/js/sample_analyses/dsjs/index.html b/jalangi2/src/js/sample_analyses/dsjs/index.html
new file mode 100644
index 00000000000..9882461469a
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/dsjs/index.html
@@ -0,0 +1,185 @@
+
+
+
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/frames/FrameAnalysis.js b/jalangi2/src/js/sample_analyses/frames/FrameAnalysis.js
new file mode 100644
index 00000000000..627c59de5dc
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/frames/FrameAnalysis.js
@@ -0,0 +1,87 @@
+/**
+ * Created by marija on 26.10.15.
+ */
+/*
+ * Copyright 2014 Samsung Information Systems America, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Author: Koushik Sen
+
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+(function (sandbox) {
+ require('./Frames.js');
+
+ function MyAnalysis() {
+
+ var frames = new sandbox.Frames();
+ sandbox.frames = frames;
+
+
+ this.literal = function (iid, val, hasGetterSetter) {
+
+ if (typeof val === 'function') {
+ frames.defineFunction(val);
+ }
+
+ };
+
+ this.declare = function (iid, name, val, isArgument, argumentIndex, isCatchParam) {
+ frames.initialize(name);
+ };
+
+ this.functionEnter = function (iid, f, dis, args) {
+ frames.functionEnter(f);
+ };
+
+
+ this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
+ frames.functionReturn();
+
+ };
+
+
+ this.scriptEnter = function (iid, instrumentedFileName, originalFileName) {
+ frames.scriptEnter();
+
+ };
+
+ this.scriptExit = function (iid, wrappedExceptionVal) {
+ frames.scriptReturn();
+
+ };
+
+
+ this.instrumentCodePre = function (iid, code) {
+ frames.evalBegin();
+
+ };
+
+
+ this.instrumentCode = function (iid, newCode, newAst) {
+ frames.evalEnd();
+
+
+ };
+
+ }
+
+ sandbox.analysis = new MyAnalysis();
+})(J$);
+
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/frames/Frames.js b/jalangi2/src/js/sample_analyses/frames/Frames.js
new file mode 100644
index 00000000000..6851c1e3644
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/frames/Frames.js
@@ -0,0 +1,118 @@
+if (typeof J$ === 'undefined') {
+ J$ = {};
+}
+
+(function (sandbox) {
+ sandbox.Frames = function () {
+ var Constants = sandbox.Constants;
+
+ var SPECIAL_PROP_FRAMES = Constants.SPECIAL_PROP3 + "FRAMES";
+ var scriptCount = 0;
+ var HOP = Constants.HOP;
+
+
+ var frame = Object.create(null);
+ var frameStack = [frame];
+ var evalFrames = [];
+
+ this.getFrameStack = function () {
+ return frameStack;
+ };
+
+
+ this.getFrame = function (name) {
+ var tmp = frame;
+ while (tmp && !HOP(tmp, name)) {
+ tmp = tmp[SPECIAL_PROP_FRAMES];
+ }
+
+ if (tmp) {
+ return tmp;
+ } else {
+ return frameStack[0]; // return global scope
+ }
+ };
+
+ this.getParentFrame = function (otherFrame) {
+ if (otherFrame) {
+ return otherFrame[SPECIAL_PROP_FRAMES];
+ } else {
+ return null;
+ }
+ };
+
+ this.getCurrentFrame = function () {
+ return frame;
+ };
+
+ this.getClosureFrame = function (fun) {
+ return fun[SPECIAL_PROP_FRAMES];
+ };
+
+
+ this.defineFunction = function (val) {
+
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(val, SPECIAL_PROP_FRAMES, {
+ enumerable: false,
+ writable: true
+ });
+ }
+ val[SPECIAL_PROP_FRAMES] = frame;
+
+ };
+
+ this.evalBegin = function () {
+ evalFrames.push(frame);
+ frame = frameStack[0];
+ };
+
+ this.evalEnd = function () {
+ frame = evalFrames.pop();
+ };
+
+
+ this.initialize = function (name) {
+ frame[name] = undefined;
+
+ };
+
+ this.functionEnter = function (val) {
+ frameStack.push(frame = Object.create(null));
+ if (Object && Object.defineProperty && typeof Object.defineProperty === 'function') {
+ Object.defineProperty(frame, SPECIAL_PROP_FRAMES, {
+ enumerable: false,
+ writable: true
+ });
+ }
+ frame[SPECIAL_PROP_FRAMES] = val[SPECIAL_PROP_FRAMES];
+
+ };
+
+ this.functionReturn = function () {
+ frameStack.pop();
+ frame = frameStack[frameStack.length - 1];
+ };
+
+ this.scriptEnter = function () {
+ scriptCount++;
+ if (scriptCount > 1) {
+ frameStack.push(frame = Object.create(null));
+ frame[SPECIAL_PROP_FRAMES] = frameStack[0];
+ }
+ };
+
+ this.scriptReturn = function () {
+ if (scriptCount > 1) {
+ frameStack.pop();
+ frame = frameStack[frameStack.length - 1];
+ }
+ scriptCount--;
+ };
+
+ };
+
+}(J$));
+
+
+
diff --git a/jalangi2/src/js/sample_analyses/pldi16/BackTrackLoop.js b/jalangi2/src/js/sample_analyses/pldi16/BackTrackLoop.js
new file mode 100644
index 00000000000..317fdf0755f
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/pldi16/BackTrackLoop.js
@@ -0,0 +1,19 @@
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+/**
+ * @author Koushik Sen
+ *
+ */
+(function (sandbox) {
+ function MyAnalysis() {
+ this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
+ return {returnVal: returnVal, wrappedExceptionVal: wrappedExceptionVal, isBacktrack: returnVal?true:false};
+ };
+ }
+ sandbox.analysis = new MyAnalysis();
+}(J$));
+
+/*
+ node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/BackTrackLoop.js tests/pldi16/BackTrackLoopTest.js
+ */
diff --git a/jalangi2/src/js/sample_analyses/pldi16/BranchCoverage.js b/jalangi2/src/js/sample_analyses/pldi16/BranchCoverage.js
new file mode 100644
index 00000000000..d5a9611b0c1
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/pldi16/BranchCoverage.js
@@ -0,0 +1,44 @@
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+/**
+ * @author Koushik Sen
+ *
+ */
+
+(function (sandbox) {
+ var trueBranches = {};
+ var falseBranches = {};
+
+ function MyAnalysis() {
+
+ this.conditional = function (iid, result) {
+ var id = J$.getGlobalIID(iid);
+ if (result)
+ trueBranches[id] = (trueBranches[id]|0) + 1;
+ else
+ falseBranches[id] = (falseBranches[id]|0) + 1;
+ };
+
+ this.endExecution = function () {
+ print(trueBranches, "True");
+ print(falseBranches, "False");
+ };
+ }
+
+ function print(map, str) {
+ for (var id in map)
+ if (map.hasOwnProperty(id)) {
+ sandbox.log(str + " branch taken at " + J$.iidToLocation(id) + " " + map[id] + " times");
+ }
+ }
+
+ sandbox.analysis = new MyAnalysis();
+}(J$));
+
+/*
+node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/BranchCoverage.js tests/pldi16/BranchCoverageTest.js
+node src/js/commands/esnstrument_cli.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/BranchCoverage.js --out /tmp/pldi16/BranchCoverageTest.html tests/pldi16/BranchCoverageTest.html
+node src/js/commands/esnstrument_cli.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/BranchCoverage.js --out /tmp/pldi16/BranchCoverageTest.js tests/pldi16/BranchCoverageTest.js
+open file:///tmp/pldi16/BranchCoverageTest.html
+*/
diff --git a/jalangi2/src/js/sample_analyses/pldi16/ChangeSematicsOfMult.js b/jalangi2/src/js/sample_analyses/pldi16/ChangeSematicsOfMult.js
new file mode 100644
index 00000000000..4f18fe232da
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/pldi16/ChangeSematicsOfMult.js
@@ -0,0 +1,30 @@
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+/**
+ * @author Koushik Sen
+ *
+ */
+
+(function (sandbox) {
+ function MyAnalysis() {
+
+ this.binaryPre = function (iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed) {
+ if (op === "*")
+ return {op: op, left: left, right: right, skip: true};
+ };
+
+ this.binary = function (iid, op, left, right, result, isOpAssign, isSwitchCaseComparison, isComputed) {
+ if (op === "*")
+ return {result: left+right};
+ };
+
+ }
+
+ sandbox.analysis = new MyAnalysis();
+}(J$));
+
+/*
+ node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/ChangeSematicsOfMult.js tests/pldi16/ChangeSematicsOfMultTest.js
+ */
+
diff --git a/jalangi2/src/js/sample_analyses/pldi16/CheckUndefinedConcatenatedToString.js b/jalangi2/src/js/sample_analyses/pldi16/CheckUndefinedConcatenatedToString.js
new file mode 100644
index 00000000000..1382ee1ce5c
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/pldi16/CheckUndefinedConcatenatedToString.js
@@ -0,0 +1,34 @@
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+/**
+ * @author Koushik Sen
+ *
+ */
+(function (sandbox) {
+ function MyAnalysis() {
+ var logs = [];
+
+ this.binary = function (iid, op, left, right, result, isOpAssign, isSwitchCaseComparison, isComputed) {
+ if (op === '+' && typeof result === 'string' && (left === undefined || right === undefined))
+ logs.push(J$.getGlobalIID(iid));
+ };
+
+ this.endExecution = function () {
+ for (var i = 0; i < logs.length; i++)
+ sandbox.log("Concatenated undefined with string at " + J$.iidToLocation(logs[i]));
+ };
+
+ }
+
+
+ sandbox.analysis = new MyAnalysis();
+}(J$));
+
+
+/*
+ node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/CheckUndefinedConcatenatedToString.js tests/pldi16/CheckUndefinedConcatenatedToStringTest.js
+ node src/js/commands/esnstrument_cli.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/CheckUndefinedConcatenatedToString.js --out /tmp/pldi16/CheckUndefinedConcatenatedToStringTest.html tests/pldi16/CheckUndefinedConcatenatedToStringTest.html
+ node src/js/commands/esnstrument_cli.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/CheckUndefinedConcatenatedToString.js --out /tmp/pldi16/CheckUndefinedConcatenatedToStringTest.js tests/pldi16/CheckUndefinedConcatenatedToStringTest.js
+ open file:///tmp/pldi16/CheckUndefinedConcatenatedToStringTest.html
+ */
\ No newline at end of file
diff --git a/jalangi2/src/js/sample_analyses/pldi16/CountObjectsPerAllocationSite.js b/jalangi2/src/js/sample_analyses/pldi16/CountObjectsPerAllocationSite.js
new file mode 100644
index 00000000000..7cc44740799
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/pldi16/CountObjectsPerAllocationSite.js
@@ -0,0 +1,46 @@
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+/**
+ * @author Koushik Sen
+ *
+ */
+(function (sandbox) {
+ var allocCount = {};
+
+ function MyAnalysis() {
+
+ this.literal = function (iid, val, hasGetterSetter) {
+ var id = J$.getGlobalIID(iid);
+ if (typeof val === 'object')
+ allocCount[id] = (allocCount[id] | 0) + 1;
+ };
+
+ this.invokeFunPre = function (iid, f, base, args, isConstructor, isMethod, functionIid, functionSid) {
+ var id = J$.getGlobalIID(iid);
+ if (isConstructor)
+ allocCount[id] = (allocCount[id] | 0) + 1;
+ };
+
+ this.endExecution = function () {
+ print(allocCount);
+ };
+ }
+
+ function print(map) {
+ for (var id in map)
+ if (map.hasOwnProperty(id)) {
+ sandbox.log("Object allocated at " + J$.iidToLocation(id)+" = "+map[id]);
+
+ }
+ }
+
+ sandbox.analysis = new MyAnalysis();
+}(J$));
+
+/*
+ node src/js/commands/jalangi.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/CountObjectsPerAllocationSite.js tests/pldi16/CountObjectsPerAllocationSiteTest.js
+ node src/js/commands/esnstrument_cli.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/CountObjectsPerAllocationSite.js --out /tmp/pldi16/CountObjectsPerAllocationSiteTest.html tests/pldi16/CountObjectsPerAllocationSiteTest.html
+ node src/js/commands/esnstrument_cli.js --inlineIID --inlineSource --analysis src/js/sample_analyses/pldi16/CountObjectsPerAllocationSite.js --out /tmp/pldi16/CountObjectsPerAllocationSiteTest.js tests/pldi16/CountObjectsPerAllocationSiteTest.js
+ open file:///tmp/pldi16/CountObjectsPerAllocationSiteTest.html
+ */
diff --git a/jalangi2/src/js/sample_analyses/pldi16/LogLoadStore.js b/jalangi2/src/js/sample_analyses/pldi16/LogLoadStore.js
new file mode 100644
index 00000000000..31591565687
--- /dev/null
+++ b/jalangi2/src/js/sample_analyses/pldi16/LogLoadStore.js
@@ -0,0 +1,95 @@
+// do not remove the following comment
+// JALANGI DO NOT INSTRUMENT
+
+/**
+ * @author Koushik Sen
+ *
+ */
+
+(function (sandbox) {
+
+ if (sandbox.Constants.isBrowser) {
+ sandbox.Results = {};
+ }
+
+ function MyAnalysis() {
+ var indentationCount = 0;
+ var cacheCount = 0;
+ var cacheIndentStr = "";
+
+ var logs = [];
+
+ function log(str) {
+ if (cacheCount !== indentationCount) {
+ cacheIndentStr = "";
+ for (var i = 0; i < indentationCount; i++) {
+ cacheIndentStr += " ";
+ }
+ cacheCount = indentationCount;
+ }
+ if (sandbox.Results) {
+ logs.push("