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 @@ + + + + + Class: MyAnalysis + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+

Class: MyAnalysis

+ + + + +
+ +
+

+ MyAnalysis +

+ +
+ +
+
+ + + + +
+
+

+ + new MyAnalysis() +

+ + + + +
+ + +
+
+ + +
+

+ 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. +

+
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+
+

+ + _return(iid, val){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before a value is returned from a function using the return keyword. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
val + + +* + + + + + + Value to be returned
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + | + + undefined + + + - If an object is returned, the value to be returned is +replaced with the value stored in the result property of the object.
+ + + + +
+ + + +
+
+

+ + _throw(iid, val){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before a value is thrown using the throw keyword. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
val + + +* + + + + + + Value to be thrown
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + | + + undefined + + + - If an object is returned, the value to be thrown is +replaced with the value stored in the result property of the object.
+ + + + +
+ + + +
+
+

+ + _with(iid, val){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called when a with statement is executed +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
val + + +* + + + + + + Value used as an argument to with
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + | + + 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.
+ + + + +
+ + + +
+
+

+ + binary(iid, op, left, right, result, isOpAssign, isSwitchCaseComparison, isComputed){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a binary operation. Binary operations include +, -, *, /, %, &, |, ^, +<<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + binaryPre(iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ 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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + conditional(iid, result){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a condition check before branching. Branching can happen in various statements +including if-then-else, switch-case, while, for, ||, &&, ?:. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
result + + +* + + + + + + The value of the conditional expression
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + declare(iid, name, val, isArgument, argumentIndex, isCatchParam){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ 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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + endExecution(){undefined} +

+ + + + +
+ + +
+
+ + +
+ 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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + undefined + + + - Any return value is ignored
+ + + + +
+ + + +
+
+

+ + endExpression(iid){undefined} +

+ + + + +
+ + +
+
+ + +
+ 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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + undefined + + + - Any return value is ignored
+ + + + +
+ + + +
+
+

+ + forinObject(iid, val){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called when a for-in loop is used to iterate the properties of an object. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
val + + +* + + + + + + Objects whose properties are iterated in a for-in loop.
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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) {}
+ + + +
+ + + +
+
+

+ + functionEnter(iid, f, dis, args){undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before the execution of a function body starts. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
f + + +function + + + + + + The function object whose body is about to get executed
dis + + +* + + + + + + The value of the this variable in the function body
args + + +Array + + + + + + List of the arguments with which the function is called
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + undefined + + + - Any return value is ignored
+ + + + +
+ + + +
+
+

+ + functionExit(iid, returnVal, wrappedExceptionVal){Object} +

+ + + + +
+ + +
+
+ + +
+ This callback is called when the execution of a function body completes +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + getField(iid, base, offset, val, isComputed, isOpAssign, isMethodCall){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a property of an object is accessed. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + getFieldPre(iid, base, offset, isComputed, isOpAssign, isMethodCall){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before a property of an object is accessed. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + instrumentCode(iid, newCode, newAst, isDirect){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a string passed as an argument to eval or Function is instrumented. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
newCode + + +* + + + + + + Instrumented code
newAst + + +Object + + + + + + The AST of the instrumented code
isDirect + + +boolean + + + + + + true if this is a direct call to eval
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + | + + undefined + + + - If an object is returned, the instrumented code is +replaced with the value stored in the result property of the object.
+ + + + +
+ + + +
+
+

+ + instrumentCodePre(iid, code, isDirect){Object} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before a string passed as an argument to eval or Function is instrumented. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + invokeFun(iid, f, base, args, result, isConstructor, isMethod, functionIid, functionSid){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a function, method, or constructor invocation. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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;
+}
+ + + +
+ + + +
+
+

+ + invokeFunPre(iid, f, base, args, isConstructor, isMethod, functionIid, functionSid){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ 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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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);
+}
+ + + +
+ + + +
+
+

+ + literal(iid, val, hasGetterSetter){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ 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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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(cb) +

+ + + + +
+ + +
+
+ + +
+ 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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+
+

+ + putField(iid, base, offset, val, isComputed, isOpAssign){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a property of an object is written. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + putFieldPre(iid, base, offset, val, isComputed, isOpAssign){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before a property of an object is written. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + read(iid, name, val, isGlobal, isScriptLocal){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a variable is read. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
name + + +string + + + + + + Name of the variable being read
val + + +* + + + + + + Value read from the variable
isGlobal + + +boolean + + + + + + True if the variable is not declared using var (e.g. console)
isScriptLocal + + +boolean + + + + + + True if the variable is declared in the global scope using var
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + | + + 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.
+ + + + +
+ + + +
+
+

+ + runInstrumentedFunctionBody(iid, f, functionIid, functionSid){boolean} +

+ + + + +
+ + +
+
+ + +
+ 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 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + boolean + + + - If true is returned the instrumented function body is executed, otherwise the +uninstrumented function body is executed.
+ + + + +
+ + + +
+
+

+ + scriptEnter(iid, instrumentedFileName, originalFileName) +

+ + + + +
+ + +
+
+ + +
+ This callback is called before the execution of a JavaScript file +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
instrumentedFileName + + +string + + + + + + Name of the instrumented script file
originalFileName + + +string + + + + + + Name of the original script file
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + +
+
+

+ + scriptExit(iid, wrappedExceptionVal){Object} +

+ + + + +
+ + +
+
+ + +
+ This callback is called when the execution of a JavaScript file completes +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
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:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + unary(iid, op, left, result){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called after a unary operation. Unary operations include +, -, ~, !, typeof, void. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
op + + +string + + + + + + Operation to be performed
left + + +* + + + + + + Left operand
result + + +* + + + + + + The result of the unary operation
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + | + + 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.
+ + + + +
+ + + +
+
+

+ + unaryPre(iid, op, left){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before a unary operation. Unary operations include +, -, ~, !, typeof, void. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
op + + +string + + + + + + Operation to be performed
left + + +* + + + + + + Left operand
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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.
+ + + + +
+ + + +
+
+

+ + write(iid, name, val, lhs, isGlobal, isScriptLocal){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This callback is called before a variable is written. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iid + + +number + + + + + + Static unique instruction identifier of this callback
name + + +string + + + + + + Name of the variable being read
val + + +* + + + + + + Value to be written to the variable
lhs + + +* + + + + + + Value stored in the variable before the write operation
isGlobal + + +boolean + + + + + + True if the variable is not declared using var (e.g. console)
isScriptLocal + + +boolean + + + + + + True if the variable is declared in the global scope using var
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + | + + 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.
+ + + + +
+ +
+ + + + + +
+ +
+ + + + + + + + +
+
+ + + + + \ No newline at end of file diff --git a/jalangi2/docs/SMemory.html b/jalangi2/docs/SMemory.html new file mode 100644 index 00000000000..1d4475894f4 --- /dev/null +++ b/jalangi2/docs/SMemory.html @@ -0,0 +1,1203 @@ + + + + + Class: SMemory + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+

Class: SMemory

+ + + + +
+ +
+

+ SMemory +

+ +
+ +
+
+ + + + +
+
+

+ + new SMemory() +

+ + + + +
+ + +
+
+ + +
+

+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. +

+

+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+
+

+ + getActualObjectOrFunctionFromShadowObjectOrFrame(obj){*} +

+ + + + +
+ + +
+
+ + +
+ Given a shadow object, it returns the actual object. +Given a shadow frame, it returns the function whose invocation created the frame. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
obj + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + * + + +
+ + + + +
+ + + +
+
+

+ + getFrame(name){Object} +

+ + + + +
+ + +
+
+ + +
+ 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"); +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + + + Name of the variable whose owner activation frame's shadow object we want to retrieve
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + + + - The shadow object of the activation frame owning the variable.
+ + + + +
+ + + +
+
+

+ + getIDFromShadowObjectOrFrame(obj){number|undefined} +

+ + + + +
+ + +
+
+ + +
+ 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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
obj + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + number + | + + undefined + + +
+ + + + +
+ + + +
+
+

+ + getShadowFrame(name){Object} +

+ + + + +
+ + +
+
+ + +
+ This method returns the shadow object associated with the activation frame that contains the variable "name". +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + + + Name of the variable whose owner activation frame's shadow object we want to retrieve
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + + + - The shadow object of the activation frame owning the variable.
+ + + + +
+ + + +
+
+

+ + getShadowObject(obj, prop, isGetField){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. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
obj + + + + The base object
prop + + + + The property name
isGetField + + + + True if the property access is a getField operation
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + Object + + +
+ + + + +
+ + + +
+
+

+ + getShadowObjectOfObject(val){Object|undefined} +

+ + + + +
+ + +
+
+ + +
+ This method returns the shadow object associated with the argument. If the argument cannot be associated with a shadow +object, the function returns undefined. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
val + + + + The object whose shadow object the function returns
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+

Index

+ + + + + + +

+ + + + + + + + + + + + + + + + + + + +
+ +
+

+ analysisCallbackTemplate.js +

+ +
+ +
+
+ + + + +
A template for writing a Jalangi 2 analysis
+ + + +
+ + + + + + + + + +
Author:
+
+
    +
  • Koushik Sen
  • +
+
+ + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+

+ SMemory.js +

+ +
+ +
+
+ + + + +
A library to associate shadow objects and unique ids to JavaScript objects and activation frames.
+ + + +
+ + + + + + + + + +
Author:
+
+
    +
  • Koushik Sen
  • +
+
+ + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ + + + + \ No newline at end of file diff --git a/jalangi2/docs/jalangi-pldi16.pptx b/jalangi2/docs/jalangi-pldi16.pptx new file mode 100755 index 00000000000..577c0d3535d Binary files /dev/null and b/jalangi2/docs/jalangi-pldi16.pptx differ diff --git a/jalangi2/docs/scripts/URI.js b/jalangi2/docs/scripts/URI.js new file mode 100644 index 00000000000..91b01ee4ee4 --- /dev/null +++ b/jalangi2/docs/scripts/URI.js @@ -0,0 +1,1429 @@ +/*! + * URI.js - Mutating URLs + * + * Version: 1.8.3 + * + * Author: Rodney Rehm + * Web: http://medialize.github.com/URI.js/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */ +(function(root, factory) { + // https://github.com/umdjs/umd/blob/master/returnExports.js + if (typeof exports === 'object') { + // Node + module.exports = factory(require('./punycode'), require('./IPv6'), require('./SecondLevelDomains')); + } else if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['./punycode', './IPv6', './SecondLevelDomains'], factory); + } else { + // Browser globals (root is window) + root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains); + } +}(this, function(punycode, IPv6, SLD) { + "use strict"; + + function URI(url, base) { + // Allow instantiation without the 'new' keyword + if (!(this instanceof URI)) { + return new URI(url, base); + } + if (url === undefined) { + if (typeof location !== 'undefined') { + url = location.href + ""; + } else { + url = ""; + } + } + this.href(url); + // resolve to base according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor + if (base !== undefined) { + return this.absoluteTo(base); + } + return this; + }; + var p = URI.prototype; + var hasOwn = Object.prototype.hasOwnProperty; + + function escapeRegEx(string) { + // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963 + return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); + } + + function isArray(obj) { + return String(Object.prototype.toString.call(obj)) === "[object Array]"; + } + + function filterArrayValues(data, value) { + var lookup = {}; + var i, length; + if (isArray(value)) { + for (i = 0, length = value.length; i < length; i++) { + lookup[value[i]] = true; + } + } else { + lookup[value] = true; + } + for (i = 0, length = data.length; i < length; i++) { + if (lookup[data[i]] !== undefined) { + data.splice(i, 1); + length--; + i--; + } + } + return data; + } + URI._parts = function() { + return { + protocol: null, + username: null, + password: null, + hostname: null, + urn: null, + port: null, + path: null, + query: null, + fragment: null, + // state + duplicateQueryParameters: URI.duplicateQueryParameters + }; + }; + // state: allow duplicate query parameters (a=1&a=1) + URI.duplicateQueryParameters = false; + // static properties + URI.protocol_expression = /^[a-z][a-z0-9-+-]*$/i; + URI.idn_expression = /[^a-z0-9\.-]/i; + URI.punycode_expression = /(xn--)/i; + // well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care? + URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; + // credits to Rich Brown + // source: http://forums.intermapper.com/viewtopic.php?p=1096#1096 + // specification: http://www.ietf.org/rfc/rfc4291.txt + URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/; + // gruber revised expression - http://rodneyrehm.de/t/url-regex.html + URI.find_uri_expression = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig; + // http://www.iana.org/assignments/uri-schemes.html + // http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports + URI.defaultPorts = { + http: "80", + https: "443", + ftp: "21", + gopher: "70", + ws: "80", + wss: "443" + }; + // allowed hostname characters according to RFC 3986 + // ALPHA DIGIT "-" "." "_" "~" "!" "$" "&" "'" "(" ")" "*" "+" "," ";" "=" %encoded + // I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . - + URI.invalid_hostname_characters = /[^a-zA-Z0-9\.-]/; + // encoding / decoding according to RFC3986 + + function strictEncodeURIComponent(string) { + // see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent + return encodeURIComponent(string).replace(/[!'()*]/g, escape).replace(/\*/g, "%2A"); + } + URI.encode = strictEncodeURIComponent; + URI.decode = decodeURIComponent; + URI.iso8859 = function() { + URI.encode = escape; + URI.decode = unescape; + }; + URI.unicode = function() { + URI.encode = strictEncodeURIComponent; + URI.decode = decodeURIComponent; + }; + URI.characters = { + pathname: { + encode: { + // RFC3986 2.1: For consistency, URI producers and normalizers should + // use uppercase hexadecimal digits for all percent-encodings. + expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig, + map: { + // -._~!'()* + "%24": "$", + "%26": "&", + "%2B": "+", + "%2C": ",", + "%3B": ";", + "%3D": "=", + "%3A": ":", + "%40": "@" + } + }, + decode: { + expression: /[\/\?#]/g, + map: { + "/": "%2F", + "?": "%3F", + "#": "%23" + } + } + }, + reserved: { + encode: { + // RFC3986 2.1: For consistency, URI producers and normalizers should + // use uppercase hexadecimal digits for all percent-encodings. + expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig, + map: { + // gen-delims + "%3A": ":", + "%2F": "/", + "%3F": "?", + "%23": "#", + "%5B": "[", + "%5D": "]", + "%40": "@", + // sub-delims + "%21": "!", + "%24": "$", + "%26": "&", + "%27": "'", + "%28": "(", + "%29": ")", + "%2A": "*", + "%2B": "+", + "%2C": ",", + "%3B": ";", + "%3D": "=" + } + } + } + }; + URI.encodeQuery = function(string) { + return URI.encode(string + "").replace(/%20/g, '+'); + }; + URI.decodeQuery = function(string) { + return URI.decode((string + "").replace(/\+/g, '%20')); + }; + URI.recodePath = function(string) { + var segments = (string + "").split('/'); + for (var i = 0, length = segments.length; i < length; i++) { + segments[i] = URI.encodePathSegment(URI.decode(segments[i])); + } + return segments.join('/'); + }; + URI.decodePath = function(string) { + var segments = (string + "").split('/'); + for (var i = 0, length = segments.length; i < length; i++) { + segments[i] = URI.decodePathSegment(segments[i]); + } + return segments.join('/'); + }; + // generate encode/decode path functions + var _parts = { + 'encode': 'encode', + 'decode': 'decode' + }; + var _part; + var generateAccessor = function(_group, _part) { + return function(string) { + return URI[_part](string + "").replace(URI.characters[_group][_part].expression, function(c) { + return URI.characters[_group][_part].map[c]; + }); + }; + }; + for (_part in _parts) { + URI[_part + "PathSegment"] = generateAccessor("pathname", _parts[_part]); + } + URI.encodeReserved = generateAccessor("reserved", "encode"); + URI.parse = function(string, parts) { + var pos, t; + if (!parts) { + parts = {}; + } + // [protocol"://"[username[":"password]"@"]hostname[":"port]"/"?][path]["?"querystring]["#"fragment] + // extract fragment + pos = string.indexOf('#'); + if (pos > -1) { + // escaping? + parts.fragment = string.substring(pos + 1) || null; + string = string.substring(0, pos); + } + // extract query + pos = string.indexOf('?'); + if (pos > -1) { + // escaping? + parts.query = string.substring(pos + 1) || null; + string = string.substring(0, pos); + } + // extract protocol + if (string.substring(0, 2) === '//') { + // relative-scheme + parts.protocol = ''; + string = string.substring(2); + // extract "user:pass@host:port" + string = URI.parseAuthority(string, parts); + } else { + pos = string.indexOf(':'); + if (pos > -1) { + parts.protocol = string.substring(0, pos); + if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) { + // : may be within the path + parts.protocol = undefined; + } else if (parts.protocol === 'file') { + // the file scheme: does not contain an authority + string = string.substring(pos + 3); + } else if (string.substring(pos + 1, pos + 3) === '//') { + string = string.substring(pos + 3); + // extract "user:pass@host:port" + string = URI.parseAuthority(string, parts); + } else { + string = string.substring(pos + 1); + parts.urn = true; + } + } + } + // what's left must be the path + parts.path = string; + // and we're done + return parts; + }; + URI.parseHost = function(string, parts) { + // extract host:port + var pos = string.indexOf('/'); + var bracketPos; + var t; + if (pos === -1) { + pos = string.length; + } + if (string[0] === "[") { + // IPv6 host - http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6 + // I claim most client software breaks on IPv6 anyways. To simplify things, URI only accepts + // IPv6+port in the format [2001:db8::1]:80 (for the time being) + bracketPos = string.indexOf(']'); + parts.hostname = string.substring(1, bracketPos) || null; + parts.port = string.substring(bracketPos + 2, pos) || null; + } else if (string.indexOf(':') !== string.lastIndexOf(':')) { + // IPv6 host contains multiple colons - but no port + // this notation is actually not allowed by RFC 3986, but we're a liberal parser + parts.hostname = string.substring(0, pos) || null; + parts.port = null; + } else { + t = string.substring(0, pos).split(':'); + parts.hostname = t[0] || null; + parts.port = t[1] || null; + } + if (parts.hostname && string.substring(pos)[0] !== '/') { + pos++; + string = "/" + string; + } + return string.substring(pos) || '/'; + }; + URI.parseAuthority = function(string, parts) { + string = URI.parseUserinfo(string, parts); + return URI.parseHost(string, parts); + }; + URI.parseUserinfo = function(string, parts) { + // extract username:password + var pos = string.indexOf('@'); + var firstSlash = string.indexOf('/'); + var t; + // authority@ must come before /path + if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) { + t = string.substring(0, pos).split(':'); + parts.username = t[0] ? URI.decode(t[0]) : null; + t.shift(); + parts.password = t[0] ? URI.decode(t.join(':')) : null; + string = string.substring(pos + 1); + } else { + parts.username = null; + parts.password = null; + } + return string; + }; + URI.parseQuery = function(string) { + if (!string) { + return {}; + } + // throw out the funky business - "?"[name"="value"&"]+ + string = string.replace(/&+/g, '&').replace(/^\?*&*|&+$/g, ''); + if (!string) { + return {}; + } + var items = {}; + var splits = string.split('&'); + var length = splits.length; + var v, name, value; + for (var i = 0; i < length; i++) { + v = splits[i].split('='); + name = URI.decodeQuery(v.shift()); + // no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters + value = v.length ? URI.decodeQuery(v.join('=')) : null; + if (items[name]) { + if (typeof items[name] === "string") { + items[name] = [items[name]]; + } + items[name].push(value); + } else { + items[name] = value; + } + } + return items; + }; + URI.build = function(parts) { + var t = ""; + if (parts.protocol) { + t += parts.protocol + ":"; + } + if (!parts.urn && (t || parts.hostname)) { + t += '//'; + } + t += (URI.buildAuthority(parts) || ''); + if (typeof parts.path === "string") { + if (parts.path[0] !== '/' && typeof parts.hostname === "string") { + t += '/'; + } + t += parts.path; + } + if (typeof parts.query === "string" && parts.query) { + t += '?' + parts.query; + } + if (typeof parts.fragment === "string" && parts.fragment) { + t += '#' + parts.fragment; + } + return t; + }; + URI.buildHost = function(parts) { + var t = ""; + if (!parts.hostname) { + return ""; + } else if (URI.ip6_expression.test(parts.hostname)) { + if (parts.port) { + t += "[" + parts.hostname + "]:" + parts.port; + } else { + // don't know if we should always wrap IPv6 in [] + // the RFC explicitly says SHOULD, not MUST. + t += parts.hostname; + } + } else { + t += parts.hostname; + if (parts.port) { + t += ':' + parts.port; + } + } + return t; + }; + URI.buildAuthority = function(parts) { + return URI.buildUserinfo(parts) + URI.buildHost(parts); + }; + URI.buildUserinfo = function(parts) { + var t = ""; + if (parts.username) { + t += URI.encode(parts.username); + if (parts.password) { + t += ':' + URI.encode(parts.password); + } + t += "@"; + } + return t; + }; + URI.buildQuery = function(data, duplicates) { + // according to http://tools.ietf.org/html/rfc3986 or http://labs.apache.org/webarch/uri/rfc/rfc3986.html + // being »-._~!$&'()*+,;=:@/?« %HEX and alnum are allowed + // the RFC explicitly states ?/foo being a valid use case, no mention of parameter syntax! + // URI.js treats the query string as being application/x-www-form-urlencoded + // see http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type + var t = ""; + var unique, key, i, length; + for (key in data) { + if (hasOwn.call(data, key) && key) { + if (isArray(data[key])) { + unique = {}; + for (i = 0, length = data[key].length; i < length; i++) { + if (data[key][i] !== undefined && unique[data[key][i] + ""] === undefined) { + t += "&" + URI.buildQueryParameter(key, data[key][i]); + if (duplicates !== true) { + unique[data[key][i] + ""] = true; + } + } + } + } else if (data[key] !== undefined) { + t += '&' + URI.buildQueryParameter(key, data[key]); + } + } + } + return t.substring(1); + }; + URI.buildQueryParameter = function(name, value) { + // http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type -- application/x-www-form-urlencoded + // don't append "=" for null values, according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#url-parameter-serialization + return URI.encodeQuery(name) + (value !== null ? "=" + URI.encodeQuery(value) : ""); + }; + URI.addQuery = function(data, name, value) { + if (typeof name === "object") { + for (var key in name) { + if (hasOwn.call(name, key)) { + URI.addQuery(data, key, name[key]); + } + } + } else if (typeof name === "string") { + if (data[name] === undefined) { + data[name] = value; + return; + } else if (typeof data[name] === "string") { + data[name] = [data[name]]; + } + if (!isArray(value)) { + value = [value]; + } + data[name] = data[name].concat(value); + } else { + throw new TypeError("URI.addQuery() accepts an object, string as the name parameter"); + } + }; + URI.removeQuery = function(data, name, value) { + var i, length, key; + if (isArray(name)) { + for (i = 0, length = name.length; i < length; i++) { + data[name[i]] = undefined; + } + } else if (typeof name === "object") { + for (key in name) { + if (hasOwn.call(name, key)) { + URI.removeQuery(data, key, name[key]); + } + } + } else if (typeof name === "string") { + if (value !== undefined) { + if (data[name] === value) { + data[name] = undefined; + } else if (isArray(data[name])) { + data[name] = filterArrayValues(data[name], value); + } + } else { + data[name] = undefined; + } + } else { + throw new TypeError("URI.addQuery() accepts an object, string as the first parameter"); + } + }; + URI.commonPath = function(one, two) { + var length = Math.min(one.length, two.length); + var pos; + // find first non-matching character + for (pos = 0; pos < length; pos++) { + if (one[pos] !== two[pos]) { + pos--; + break; + } + } + if (pos < 1) { + return one[0] === two[0] && one[0] === '/' ? '/' : ''; + } + // revert to last / + if (one[pos] !== '/') { + pos = one.substring(0, pos).lastIndexOf('/'); + } + return one.substring(0, pos + 1); + }; + URI.withinString = function(string, callback) { + // expression used is "gruber revised" (@gruber v2) determined to be the best solution in + // a regex sprint we did a couple of ages ago at + // * http://mathiasbynens.be/demo/url-regex + // * http://rodneyrehm.de/t/url-regex.html + return string.replace(URI.find_uri_expression, callback); + }; + URI.ensureValidHostname = function(v) { + // Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986) + // they are not part of DNS and therefore ignored by URI.js + if (v.match(URI.invalid_hostname_characters)) { + // test punycode + if (!punycode) { + throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-] and Punycode.js is not available"); + } + if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) { + throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-]"); + } + } + }; + p.build = function(deferBuild) { + if (deferBuild === true) { + this._deferred_build = true; + } else if (deferBuild === undefined || this._deferred_build) { + this._string = URI.build(this._parts); + this._deferred_build = false; + } + return this; + }; + p.clone = function() { + return new URI(this); + }; + p.valueOf = p.toString = function() { + return this.build(false)._string; + }; + // generate simple accessors + _parts = { + protocol: 'protocol', + username: 'username', + password: 'password', + hostname: 'hostname', + port: 'port' + }; + generateAccessor = function(_part) { + return function(v, build) { + if (v === undefined) { + return this._parts[_part] || ""; + } else { + this._parts[_part] = v; + this.build(!build); + return this; + } + }; + }; + for (_part in _parts) { + p[_part] = generateAccessor(_parts[_part]); + } + // generate accessors with optionally prefixed input + _parts = { + query: '?', + fragment: '#' + }; + generateAccessor = function(_part, _key) { + return function(v, build) { + if (v === undefined) { + return this._parts[_part] || ""; + } else { + if (v !== null) { + v = v + ""; + if (v[0] === _key) { + v = v.substring(1); + } + } + this._parts[_part] = v; + this.build(!build); + return this; + } + }; + }; + for (_part in _parts) { + p[_part] = generateAccessor(_part, _parts[_part]); + } + // generate accessors with prefixed output + _parts = { + search: ['?', 'query'], + hash: ['#', 'fragment'] + }; + generateAccessor = function(_part, _key) { + return function(v, build) { + var t = this[_part](v, build); + return typeof t === "string" && t.length ? (_key + t) : t; + }; + }; + for (_part in _parts) { + p[_part] = generateAccessor(_parts[_part][1], _parts[_part][0]); + } + p.pathname = function(v, build) { + if (v === undefined || v === true) { + var res = this._parts.path || (this._parts.urn ? '' : '/'); + return v ? URI.decodePath(res) : res; + } else { + this._parts.path = v ? URI.recodePath(v) : "/"; + this.build(!build); + return this; + } + }; + p.path = p.pathname; + p.href = function(href, build) { + var key; + if (href === undefined) { + return this.toString(); + } + this._string = ""; + this._parts = URI._parts(); + var _URI = href instanceof URI; + var _object = typeof href === "object" && (href.hostname || href.path); + // window.location is reported to be an object, but it's not the sort + // of object we're looking for: + // * location.protocol ends with a colon + // * location.query != object.search + // * location.hash != object.fragment + // simply serializing the unknown object should do the trick + // (for location, not for everything...) + if (!_URI && _object && Object.prototype.toString.call(href) !== "[object Object]") { + href = href.toString(); + } + if (typeof href === "string") { + this._parts = URI.parse(href, this._parts); + } else if (_URI || _object) { + var src = _URI ? href._parts : href; + for (key in src) { + if (hasOwn.call(this._parts, key)) { + this._parts[key] = src[key]; + } + } + } else { + throw new TypeError("invalid input"); + } + this.build(!build); + return this; + }; + // identification accessors + p.is = function(what) { + var ip = false; + var ip4 = false; + var ip6 = false; + var name = false; + var sld = false; + var idn = false; + var punycode = false; + var relative = !this._parts.urn; + if (this._parts.hostname) { + relative = false; + ip4 = URI.ip4_expression.test(this._parts.hostname); + ip6 = URI.ip6_expression.test(this._parts.hostname); + ip = ip4 || ip6; + name = !ip; + sld = name && SLD && SLD.has(this._parts.hostname); + idn = name && URI.idn_expression.test(this._parts.hostname); + punycode = name && URI.punycode_expression.test(this._parts.hostname); + } + switch (what.toLowerCase()) { + case 'relative': + return relative; + case 'absolute': + return !relative; + // hostname identification + case 'domain': + case 'name': + return name; + case 'sld': + return sld; + case 'ip': + return ip; + case 'ip4': + case 'ipv4': + case 'inet4': + return ip4; + case 'ip6': + case 'ipv6': + case 'inet6': + return ip6; + case 'idn': + return idn; + case 'url': + return !this._parts.urn; + case 'urn': + return !!this._parts.urn; + case 'punycode': + return punycode; + } + return null; + }; + // component specific input validation + var _protocol = p.protocol; + var _port = p.port; + var _hostname = p.hostname; + p.protocol = function(v, build) { + if (v !== undefined) { + if (v) { + // accept trailing :// + v = v.replace(/:(\/\/)?$/, ''); + if (v.match(/[^a-zA-z0-9\.+-]/)) { + throw new TypeError("Protocol '" + v + "' contains characters other than [A-Z0-9.+-]"); + } + } + } + return _protocol.call(this, v, build); + }; + p.scheme = p.protocol; + p.port = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v !== undefined) { + if (v === 0) { + v = null; + } + if (v) { + v += ""; + if (v[0] === ":") { + v = v.substring(1); + } + if (v.match(/[^0-9]/)) { + throw new TypeError("Port '" + v + "' contains characters other than [0-9]"); + } + } + } + return _port.call(this, v, build); + }; + p.hostname = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v !== undefined) { + var x = {}; + URI.parseHost(v, x); + v = x.hostname; + } + return _hostname.call(this, v, build); + }; + // compound accessors + p.host = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined) { + return this._parts.hostname ? URI.buildHost(this._parts) : ""; + } else { + URI.parseHost(v, this._parts); + this.build(!build); + return this; + } + }; + p.authority = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined) { + return this._parts.hostname ? URI.buildAuthority(this._parts) : ""; + } else { + URI.parseAuthority(v, this._parts); + this.build(!build); + return this; + } + }; + p.userinfo = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined) { + if (!this._parts.username) { + return ""; + } + var t = URI.buildUserinfo(this._parts); + return t.substring(0, t.length - 1); + } else { + if (v[v.length - 1] !== '@') { + v += '@'; + } + URI.parseUserinfo(v, this._parts); + this.build(!build); + return this; + } + }; + p.resource = function(v, build) { + var parts; + if (v === undefined) { + return this.path() + this.search() + this.hash(); + } + parts = URI.parse(v); + this._parts.path = parts.path; + this._parts.query = parts.query; + this._parts.fragment = parts.fragment; + this.build(!build); + return this; + }; + // fraction accessors + p.subdomain = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + // convenience, return "www" from "www.example.org" + if (v === undefined) { + if (!this._parts.hostname || this.is('IP')) { + return ""; + } + // grab domain and add another segment + var end = this._parts.hostname.length - this.domain().length - 1; + return this._parts.hostname.substring(0, end) || ""; + } else { + var e = this._parts.hostname.length - this.domain().length; + var sub = this._parts.hostname.substring(0, e); + var replace = new RegExp('^' + escapeRegEx(sub)); + if (v && v[v.length - 1] !== '.') { + v += "."; + } + if (v) { + URI.ensureValidHostname(v); + } + this._parts.hostname = this._parts.hostname.replace(replace, v); + this.build(!build); + return this; + } + }; + p.domain = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (typeof v === 'boolean') { + build = v; + v = undefined; + } + // convenience, return "example.org" from "www.example.org" + if (v === undefined) { + if (!this._parts.hostname || this.is('IP')) { + return ""; + } + // if hostname consists of 1 or 2 segments, it must be the domain + var t = this._parts.hostname.match(/\./g); + if (t && t.length < 2) { + return this._parts.hostname; + } + // grab tld and add another segment + var end = this._parts.hostname.length - this.tld(build).length - 1; + end = this._parts.hostname.lastIndexOf('.', end - 1) + 1; + return this._parts.hostname.substring(end) || ""; + } else { + if (!v) { + throw new TypeError("cannot set domain empty"); + } + URI.ensureValidHostname(v); + if (!this._parts.hostname || this.is('IP')) { + this._parts.hostname = v; + } else { + var replace = new RegExp(escapeRegEx(this.domain()) + "$"); + this._parts.hostname = this._parts.hostname.replace(replace, v); + } + this.build(!build); + return this; + } + }; + p.tld = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (typeof v === 'boolean') { + build = v; + v = undefined; + } + // return "org" from "www.example.org" + if (v === undefined) { + if (!this._parts.hostname || this.is('IP')) { + return ""; + } + var pos = this._parts.hostname.lastIndexOf('.'); + var tld = this._parts.hostname.substring(pos + 1); + if (build !== true && SLD && SLD.list[tld.toLowerCase()]) { + return SLD.get(this._parts.hostname) || tld; + } + return tld; + } else { + var replace; + if (!v) { + throw new TypeError("cannot set TLD empty"); + } else if (v.match(/[^a-zA-Z0-9-]/)) { + if (SLD && SLD.is(v)) { + replace = new RegExp(escapeRegEx(this.tld()) + "$"); + this._parts.hostname = this._parts.hostname.replace(replace, v); + } else { + throw new TypeError("TLD '" + v + "' contains characters other than [A-Z0-9]"); + } + } else if (!this._parts.hostname || this.is('IP')) { + throw new ReferenceError("cannot set TLD on non-domain host"); + } else { + replace = new RegExp(escapeRegEx(this.tld()) + "$"); + this._parts.hostname = this._parts.hostname.replace(replace, v); + } + this.build(!build); + return this; + } + }; + p.directory = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined || v === true) { + if (!this._parts.path && !this._parts.hostname) { + return ''; + } + if (this._parts.path === '/') { + return '/'; + } + var end = this._parts.path.length - this.filename().length - 1; + var res = this._parts.path.substring(0, end) || (this._parts.hostname ? "/" : ""); + return v ? URI.decodePath(res) : res; + } else { + var e = this._parts.path.length - this.filename().length; + var directory = this._parts.path.substring(0, e); + var replace = new RegExp('^' + escapeRegEx(directory)); + // fully qualifier directories begin with a slash + if (!this.is('relative')) { + if (!v) { + v = '/'; + } + if (v[0] !== '/') { + v = "/" + v; + } + } + // directories always end with a slash + if (v && v[v.length - 1] !== '/') { + v += '/'; + } + v = URI.recodePath(v); + this._parts.path = this._parts.path.replace(replace, v); + this.build(!build); + return this; + } + }; + p.filename = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined || v === true) { + if (!this._parts.path || this._parts.path === '/') { + return ""; + } + var pos = this._parts.path.lastIndexOf('/'); + var res = this._parts.path.substring(pos + 1); + return v ? URI.decodePathSegment(res) : res; + } else { + var mutatedDirectory = false; + if (v[0] === '/') { + v = v.substring(1); + } + if (v.match(/\.?\//)) { + mutatedDirectory = true; + } + var replace = new RegExp(escapeRegEx(this.filename()) + "$"); + v = URI.recodePath(v); + this._parts.path = this._parts.path.replace(replace, v); + if (mutatedDirectory) { + this.normalizePath(build); + } else { + this.build(!build); + } + return this; + } + }; + p.suffix = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined || v === true) { + if (!this._parts.path || this._parts.path === '/') { + return ""; + } + var filename = this.filename(); + var pos = filename.lastIndexOf('.'); + var s, res; + if (pos === -1) { + return ""; + } + // suffix may only contain alnum characters (yup, I made this up.) + s = filename.substring(pos + 1); + res = (/^[a-z0-9%]+$/i).test(s) ? s : ""; + return v ? URI.decodePathSegment(res) : res; + } else { + if (v[0] === '.') { + v = v.substring(1); + } + var suffix = this.suffix(); + var replace; + if (!suffix) { + if (!v) { + return this; + } + this._parts.path += '.' + URI.recodePath(v); + } else if (!v) { + replace = new RegExp(escapeRegEx("." + suffix) + "$"); + } else { + replace = new RegExp(escapeRegEx(suffix) + "$"); + } + if (replace) { + v = URI.recodePath(v); + this._parts.path = this._parts.path.replace(replace, v); + } + this.build(!build); + return this; + } + }; + p.segment = function(segment, v, build) { + var separator = this._parts.urn ? ':' : '/'; + var path = this.path(); + var absolute = path.substring(0, 1) === '/'; + var segments = path.split(separator); + if (typeof segment !== 'number') { + build = v; + v = segment; + segment = undefined; + } + if (segment !== undefined && typeof segment !== 'number') { + throw new Error("Bad segment '" + segment + "', must be 0-based integer"); + } + if (absolute) { + segments.shift(); + } + if (segment < 0) { + // allow negative indexes to address from the end + segment = Math.max(segments.length + segment, 0); + } + if (v === undefined) { + return segment === undefined ? segments : segments[segment]; + } else if (segment === null || segments[segment] === undefined) { + if (isArray(v)) { + segments = v; + } else if (v || (typeof v === "string" && v.length)) { + if (segments[segments.length - 1] === "") { + // empty trailing elements have to be overwritten + // to prefent results such as /foo//bar + segments[segments.length - 1] = v; + } else { + segments.push(v); + } + } + } else { + if (v || (typeof v === "string" && v.length)) { + segments[segment] = v; + } else { + segments.splice(segment, 1); + } + } + if (absolute) { + segments.unshift(""); + } + return this.path(segments.join(separator), build); + }; + // mutating query string + var q = p.query; + p.query = function(v, build) { + if (v === true) { + return URI.parseQuery(this._parts.query); + } else if (v !== undefined && typeof v !== "string") { + this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters); + this.build(!build); + return this; + } else { + return q.call(this, v, build); + } + }; + p.addQuery = function(name, value, build) { + var data = URI.parseQuery(this._parts.query); + URI.addQuery(data, name, value === undefined ? null : value); + this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters); + if (typeof name !== "string") { + build = value; + } + this.build(!build); + return this; + }; + p.removeQuery = function(name, value, build) { + var data = URI.parseQuery(this._parts.query); + URI.removeQuery(data, name, value); + this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters); + if (typeof name !== "string") { + build = value; + } + this.build(!build); + return this; + }; + p.addSearch = p.addQuery; + p.removeSearch = p.removeQuery; + // sanitizing URLs + p.normalize = function() { + if (this._parts.urn) { + return this.normalizeProtocol(false).normalizeQuery(false).normalizeFragment(false).build(); + } + return this.normalizeProtocol(false).normalizeHostname(false).normalizePort(false).normalizePath(false).normalizeQuery(false).normalizeFragment(false).build(); + }; + p.normalizeProtocol = function(build) { + if (typeof this._parts.protocol === "string") { + this._parts.protocol = this._parts.protocol.toLowerCase(); + this.build(!build); + } + return this; + }; + p.normalizeHostname = function(build) { + if (this._parts.hostname) { + if (this.is('IDN') && punycode) { + this._parts.hostname = punycode.toASCII(this._parts.hostname); + } else if (this.is('IPv6') && IPv6) { + this._parts.hostname = IPv6.best(this._parts.hostname); + } + this._parts.hostname = this._parts.hostname.toLowerCase(); + this.build(!build); + } + return this; + }; + p.normalizePort = function(build) { + // remove port of it's the protocol's default + if (typeof this._parts.protocol === "string" && this._parts.port === URI.defaultPorts[this._parts.protocol]) { + this._parts.port = null; + this.build(!build); + } + return this; + }; + p.normalizePath = function(build) { + if (this._parts.urn) { + return this; + } + if (!this._parts.path || this._parts.path === '/') { + return this; + } + var _was_relative; + var _was_relative_prefix; + var _path = this._parts.path; + var _parent, _pos; + // handle relative paths + if (_path[0] !== '/') { + if (_path[0] === '.') { + _was_relative_prefix = _path.substring(0, _path.indexOf('/')); + } + _was_relative = true; + _path = '/' + _path; + } + // resolve simples + _path = _path.replace(/(\/(\.\/)+)|\/{2,}/g, '/'); + // resolve parents + while (true) { + _parent = _path.indexOf('/../'); + if (_parent === -1) { + // no more ../ to resolve + break; + } else if (_parent === 0) { + // top level cannot be relative... + _path = _path.substring(3); + break; + } + _pos = _path.substring(0, _parent).lastIndexOf('/'); + if (_pos === -1) { + _pos = _parent; + } + _path = _path.substring(0, _pos) + _path.substring(_parent + 3); + } + // revert to relative + if (_was_relative && this.is('relative')) { + if (_was_relative_prefix) { + _path = _was_relative_prefix + _path; + } else { + _path = _path.substring(1); + } + } + _path = URI.recodePath(_path); + this._parts.path = _path; + this.build(!build); + return this; + }; + p.normalizePathname = p.normalizePath; + p.normalizeQuery = function(build) { + if (typeof this._parts.query === "string") { + if (!this._parts.query.length) { + this._parts.query = null; + } else { + this.query(URI.parseQuery(this._parts.query)); + } + this.build(!build); + } + return this; + }; + p.normalizeFragment = function(build) { + if (!this._parts.fragment) { + this._parts.fragment = null; + this.build(!build); + } + return this; + }; + p.normalizeSearch = p.normalizeQuery; + p.normalizeHash = p.normalizeFragment; + p.iso8859 = function() { + // expect unicode input, iso8859 output + var e = URI.encode; + var d = URI.decode; + URI.encode = escape; + URI.decode = decodeURIComponent; + this.normalize(); + URI.encode = e; + URI.decode = d; + return this; + }; + p.unicode = function() { + // expect iso8859 input, unicode output + var e = URI.encode; + var d = URI.decode; + URI.encode = strictEncodeURIComponent; + URI.decode = unescape; + this.normalize(); + URI.encode = e; + URI.decode = d; + return this; + }; + p.readable = function() { + var uri = this.clone(); + // removing username, password, because they shouldn't be displayed according to RFC 3986 + uri.username("").password("").normalize(); + var t = ''; + if (uri._parts.protocol) { + t += uri._parts.protocol + '://'; + } + if (uri._parts.hostname) { + if (uri.is('punycode') && punycode) { + t += punycode.toUnicode(uri._parts.hostname); + if (uri._parts.port) { + t += ":" + uri._parts.port; + } + } else { + t += uri.host(); + } + } + if (uri._parts.hostname && uri._parts.path && uri._parts.path[0] !== '/') { + t += '/'; + } + t += uri.path(true); + if (uri._parts.query) { + var q = ''; + for (var i = 0, qp = uri._parts.query.split('&'), l = qp.length; i < l; i++) { + var kv = (qp[i] || "").split('='); + q += '&' + URI.decodeQuery(kv[0]).replace(/&/g, '%26'); + if (kv[1] !== undefined) { + q += "=" + URI.decodeQuery(kv[1]).replace(/&/g, '%26'); + } + } + t += '?' + q.substring(1); + } + t += uri.hash(); + return t; + }; + // resolving relative and absolute URLs + p.absoluteTo = function(base) { + var resolved = this.clone(); + var properties = ['protocol', 'username', 'password', 'hostname', 'port']; + var basedir, i, p; + if (this._parts.urn) { + throw new Error('URNs do not have any generally defined hierachical components'); + } + if (this._parts.hostname) { + return resolved; + } + if (!(base instanceof URI)) { + base = new URI(base); + } + for (i = 0, p; p = properties[i]; i++) { + resolved._parts[p] = base._parts[p]; + } + properties = ['query', 'path']; + for (i = 0, p; p = properties[i]; i++) { + if (!resolved._parts[p] && base._parts[p]) { + resolved._parts[p] = base._parts[p]; + } + } + if (resolved.path()[0] !== '/') { + basedir = base.directory(); + resolved._parts.path = (basedir ? (basedir + '/') : '') + resolved._parts.path; + resolved.normalizePath(); + } + resolved.build(); + return resolved; + }; + p.relativeTo = function(base) { + var relative = this.clone(); + var properties = ['protocol', 'username', 'password', 'hostname', 'port']; + var common, _base, _this, _base_diff, _this_diff; + if (this._parts.urn) { + throw new Error('URNs do not have any generally defined hierachical components'); + } + if (!(base instanceof URI)) { + base = new URI(base); + } + if (this.path()[0] !== '/' || base.path()[0] !== '/') { + throw new Error('Cannot calculate common path from non-relative URLs'); + } + // determine common sub path + common = URI.commonPath(relative.path(), base.path()); + // no relation if there's nothing in common + if (!common || common === '/') { + return relative; + } + // relative paths don't have authority + for (var i = 0, p; p = properties[i]; i++) { + relative._parts[p] = null; + } + _base = base.directory(); + _this = this.directory(); + // base and this are on the same level + if (_base === _this) { + relative._parts.path = './' + relative.filename(); + return relative.build(); + } + _base_diff = _base.substring(common.length); + _this_diff = _this.substring(common.length); + // this is a descendant of base + if (_base + '/' === common) { + if (_this_diff) { + _this_diff += '/'; + } + relative._parts.path = './' + _this_diff + relative.filename(); + return relative.build(); + } + // this is a descendant of base + var parents = '../'; + var _common = new RegExp('^' + escapeRegEx(common)); + var _parents = _base.replace(_common, '/').match(/\//g).length - 1; + while (_parents--) { + parents += '../'; + } + relative._parts.path = relative._parts.path.replace(_common, parents); + return relative.build(); + }; + // comparing URIs + p.equals = function(uri) { + var one = this.clone(); + var two = new URI(uri); + var one_map = {}; + var two_map = {}; + var checked = {}; + var one_query, two_query, key; + one.normalize(); + two.normalize(); + // exact match + if (one.toString() === two.toString()) { + return true; + } + // extract query string + one_query = one.query(); + two_query = two.query(); + one.query(""); + two.query(""); + // definitely not equal if not even non-query parts match + if (one.toString() !== two.toString()) { + return false; + } + // query parameters have the same length, even if they're permutated + if (one_query.length !== two_query.length) { + return false; + } + one_map = URI.parseQuery(one_query); + two_map = URI.parseQuery(two_query); + for (key in one_map) { + if (hasOwn.call(one_map, key)) { + if (!isArray(one_map[key])) { + if (one_map[key] !== two_map[key]) { + return false; + } + } else { + if (!isArray(two_map[key])) { + return false; + } + // arrays can't be equal if they have different amount of content + if (one_map[key].length !== two_map[key].length) { + return false; + } + one_map[key].sort(); + two_map[key].sort(); + for (var i = 0, l = one_map[key].length; i < l; i++) { + if (one_map[key][i] !== two_map[key][i]) { + return false; + } + } + } + checked[key] = true; + } + } + for (key in two_map) { + if (hasOwn.call(two_map, key)) { + if (!checked[key]) { + // two contains a parameter not present in one + return false; + } + } + } + return true; + }; + // state + p.duplicateQueryParameters = function(v) { + this._parts.duplicateQueryParameters = !! v; + return this; + }; + return URI; +})); \ No newline at end of file diff --git a/jalangi2/docs/scripts/bootstrap-dropdown.js b/jalangi2/docs/scripts/bootstrap-dropdown.js new file mode 100644 index 00000000000..d04da5d7bb7 --- /dev/null +++ b/jalangi2/docs/scripts/bootstrap-dropdown.js @@ -0,0 +1,169 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#dropdowns + * ============================================================ + * Copyright 2013 Twitter, 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. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement) { + // if mobile we we use a backdrop because click events don't delegate + $('