diff --git a/.gitignore b/.gitignore index 421c4f4..2a0a940 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +dist output.csv output/ node_modules/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 29b8975..70a5ba8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,8 @@ "devDependencies": { "@types/eslint-scope": "^8.3.0", "@types/estree": "^1.0.8", - "@types/node": "^24.0.0" + "@types/node": "^24.0.0", + "classnames": "^2.5.1" } }, "node_modules/@jridgewell/gen-mapping": { @@ -424,6 +425,13 @@ "node": ">=6.0" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "dev": true, + "license": "MIT" + }, "node_modules/cli-table": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.0.2.tgz", diff --git a/package.json b/package.json index 33eb106..0f445fc 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "devDependencies": { "@types/eslint-scope": "^8.3.0", "@types/estree": "^1.0.8", - "@types/node": "^24.0.0" + "@types/node": "^24.0.0", + "classnames": "^2.5.1" } } diff --git a/src/index.mjs b/src/index.mjs index 7caf62a..4f489ab 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -4,10 +4,11 @@ import { getASTAndScope } from './ast/analysis.mjs'; import { getRequireCallsAndConstantArgs } from './calls.mjs'; import { analyze, instrumentString, instrumentDir } from 'jalangi2'; -import { readFileSync ,realpathSync} from 'node:fs'; +import { readFileSync ,realpathSync ,mkdirSync} from 'node:fs'; +import { writeFile } from 'node:fs/promises'; -import {getSliceAndInfoSync} from 'slice-js/dist/slice-code/test/helpers/utils.js'; -import { dirname,join } from 'node:path'; +import {getSliceAndInfoSync} from 'slice-js/src/slice-code/test/helpers/utils.js'; +import path, { dirname,join } from 'node:path'; /** * Call parameter generation */ @@ -19,18 +20,11 @@ function main() { const calls = getRequireCallsAndConstantArgs(scopeManager); - for (const [moduleName, callBoxes] of calls.entries()) { - if (moduleName.startsWith('.')) { - console.log('Importing', moduleName, callBoxes); - } else { - console.log(`Module "${moduleName}" - System module. FIXME skipping`); - } - } - console.log(`Call List`, calls); + logCallList(calls); + const writePromises = []; for (const [moduleName, callBox] of calls) { - // console.log(callBox); - if (!moduleName.startsWith('.')) { + if (!isRelativeModule(moduleName)) { // not relative module continue; } @@ -40,36 +34,27 @@ function main() { return [...callBox.entries()].flatMap(([methodName, methodArgsList])=>{ const methodNameNormed = methodName.substring(1); console.log("Calls for ",methodNameNormed,methodArgsList) - return methodArgsList.map(methodArgsList=>moduleExports[methodNameNormed].apply(moduleExports[methodNameNormed],methodArgsList)); + return methodArgsList.map(methodArgsList=>{ + const methodObj = methodNameNormed===''?moduleExports:moduleExports[methodNameNormed]; + methodObj.apply(moduleExports[methodNameNormed],methodArgsList) + }); }) },relatedModuleNamePath); - console.log(`Sliced code ${moduleName}\n`,slicedCode); + // console.log(`Sliced code ${moduleName}\n`,slicedCode); + const writePath = path.resolve('./dist', moduleName); + if(writePath===moduleName){ + throw Error("Will overwrite!!!!"); + } + mkdirSync(path.dirname(writePath),{recursive: true}); + console.log(`Writing to`,writePath); + + writePromises.push(writeFile(writePath,slicedCode)); + } -} -function jalangiInstrumentMain() { - const FILE_PATH = './test_src/index.cjs'; - - - const fileString = readFileSync(FILE_PATH).toString(); - const y = instrumentString(fileString, {}); - console.log(y); -} - - -/** - * Analysis POC - */ -function jalangiAnalyzeMain() { - const FILE_PATH = './test_src/index.cjs'; - - const y = analyze(FILE_PATH, ["./node_modules/jalangi2/src/js/sample_analyses/tutorial/LogAll.js", "./src_analysis/analysisCallbackTemplate.cjs"]); - // const x = 5; - y.then(yp => { - console.log("Analysis complete", yp); - }).catch(console.error).finally(kek => { - console.log("Threw error", kek); - }) + Promise.all(writePromises).then(p=>{ + console.log("write finished") + }).catch(console.log); } if (process.argv[1] === import.meta.filename) { @@ -78,3 +63,18 @@ if (process.argv[1] === import.meta.filename) { } +function logCallList(calls) { + for (const [moduleName, callBoxes] of calls.entries()) { + if (isRelativeModule(moduleName)) { + console.log('Importing', moduleName, callBoxes); + } else { + console.log(`Module "${moduleName}" - System module. FIXME skipping`); + } + } + console.log(`Call List`, calls); +} + +function isRelativeModule(moduleName) { + return moduleName.startsWith('.'); +} + diff --git a/src_analysis/analysisCallbackTemplate.cjs b/src_analysis/analysisCallbackTemplate.cjs deleted file mode 100644 index 01bede0..0000000 --- a/src_analysis/analysisCallbackTemplate.cjs +++ /dev/null @@ -1,647 +0,0 @@ -/* - * Copyright 2014 Samsung Information Systems America, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Author: Koushik Sen - -// do not remove the following comment -// JALANGI DO NOT INSTRUMENT - -/** - * @file A template for writing a Jalangi 2 analysis - * @author Koushik Sen - * - */ - -(function (sandbox) { - /** - *
- * This file is a template for writing a custom Jalangi 2 analysis. Simply copy this file and rewrite the - * callbacks that you need to implement in your analysis. Other callbacks should be removed from the file. - *
- * - *- * In the following methods (also called as callbacks) one can choose to not return anything. - * If all of the callbacks return nothing, we get a passive analysis where the - * concrete execution happens unmodified and callbacks can be used to observe the execution. - * One can choose to return suitable objects with specified properties in some callbacks - * to modify the behavior of the concrete execution. For example, one could set the skip - * property of the object returned from {@link MyAnalysis#putFieldPre} to true to skip the actual putField operation. - * Similarly, one could set the result field of the object returned from a {@link MyAnalysis#write} callback - * to modify the value that is actually written to a variable. The result field of the object - * returned from a {@link MyAnalysis#conditional} callback can be suitably set to change the control-flow of the - * program execution. In {@link MyAnalysis#functionExit} and {@link MyAnalysis#scriptExit}, - * one can set the isBacktrack property of the returned object to true to reexecute the body of - * the function from the beginning. This in conjunction with the ability to change the - * control-flow of a program enables us to explore the different paths of a function in - * symbolic execution. - *
- * - *- * Note that if process.exit() is called, then an execution terminates abnormally and a callback to - * {@link MyAnalysis#endExecution} will be skipped. - *
- * - *
- * An analysis can access the source map, which maps instruction identifiers to source locations,
- * using the global object stored in J$.smap
. Jalangi 2
- * assigns a unique id, called sid
, to each JavaScript
- * script loaded at runtime. J$.smap
maps each sid
to an object, say
- * iids
, containing source map information for the script whose id is sid
.
- * iids
has the following properties: "originalCodeFileName"
(stores the path of the original
- * script file), "instrumentedCodeFileName"
(stores the path of the instrumented script file),
- * "url"
(is optional and stores the URL of the script if it is set during instrumentation
- * using the --url option),
- * "evalSid"
(stores the sid of the script in which the eval is called in case the current script comes from
- * an eval
function call),
- * "evalIid"
(iid of the eval
function call in case the current script comes from an
- * eval
function call), "nBranches"
(the number of conditional statements
- * in the script),
- * and "code"
(a string denoting the original script code if the code is instrumented with the
- * --inlineSource option).
- * iids
also maps each iid
(which stands for instruction id, an unique id assigned
- * to each callback function inserted by Jalangi2) to an array containing
- * [beginLineNumber, beginColumnNumber, endLineNumber, endColumnNumber]
. The mapping from iids
- * to arrays is only available if the code is instrumented with
- * the --inlineIID option.
- *
- * In each callback described below, iid
denotes the unique static instruction id of the callback in the script.
- * Two callback functions inserted in two different scripts may have the same iid. In a callback function, one can access
- * the current script id using J$.sid
. One can call J$.getGlobalIID(iid)
to get a string, called
- * giid
, that statically identifies the
- * callback throughout the program. J$.getGlobalIID(iid)
returns the string J$.sid+":"+iid
.
- * J$.iidToLocation(giid)
returns a string
- * containing the original script file path, begin and end line numbers and column numbers of the code snippet
- * for which the callback with giid
was inserted.
- *
- *
- * A number of sample analyses can be found at {@link ../src/js/sample_analyses/}. Refer to {@link ../README.md} for instructions - * on running an analysis. - *
- * - * - * - * @global - * @class - */ - function MyAnalysis() { - /** - * This callback is called before a function, method, or constructor invocation. - * Note that a method invocation also triggers a {@link MyAnalysis#getFieldPre} and a - * {@link MyAnalysis#getField} callbacks. - * - * @example - * y.f(a, b, c) - * - * // the above call roughly gets instrumented as follows: - * - * var skip = false; - * var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true); - * if (aret) { - * f = aret.f; - * y = aret.y; - * args = aret.args; - * skip = aret.skip - * } - * if (!skip) { - * f.apply(y, args); - * } - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {function} f - The function object that going to be invoked - * @param {object} base - The receiver object for the function f - * @param {Array} args - The array of arguments passed to f - * @param {boolean} isConstructor - True if f is invoked as a constructor - * @param {boolean} isMethod - True if f is invoked as a method - * @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created - * @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created - * {@link MyAnalysis#functionEnter} when the function f is executed. The functionIid can be - * treated as the static identifier of the function f. Note that a given function code block can - * create several function objects, but each such object has a common functionIid, which is the iid - * that is passed to {@link MyAnalysis#functionEnter} when the function executes. - * @returns {{f: function, base: Object, args: Array, skip: boolean}|undefined} - If an object is returned and - * the skip property of the object is true, then the invocation operation is skipped. - * Original f, base, and args are replaced with that from the returned object if - * an object is returned. - * - */ - this.invokeFunPre = function (iid, f, base, args, isConstructor, isMethod, functionIid, functionSid) { - console.log("Attempting to call xyz") - return {f: f, base: base, args: args, skip: false}; - }; - - /** - * This callback is called after a function, method, or constructor invocation. - * - * @example - * x = y.f(a, b, c) - * - * // the above call roughly gets instrumented as follows: - * - * var skip = false; - * var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true); - * if (aret) { - * f = aret.f; - * y = aret.y; - * args = aret.args; - * skip = aret.skip - * } - * if (!skip) { - * result =f.apply(y, args); - * } - * aret = analysis.invokeFun(117, f, y, args, result, false, true); - * if (aret) { - * x = aret.result - * } else { - * x = result; - * } - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {function} f - The function object that was invoked - * @param {*} base - The receiver object for the function f - * @param {Array} args - The array of arguments passed to f - * @param {*} result - The value returned by the invocation - * @param {boolean} isConstructor - True if f is invoked as a constructor - * @param {boolean} isMethod - True if f is invoked as a method - * @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created - * @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created - * {@link MyAnalysis#functionEnter} when the function f is executed. functionIid can be treated as the - * static identifier of the function f. Note that a given function code block can create several function - * objects, but each such object has a common functionIid, which is the iid that is passed to - * {@link MyAnalysis#functionEnter} when the function executes. - * @returns {{result: *}| undefined} - If an object is returned, the return value of the invoked function is - * replaced with the value stored in the result property of the object. This enables one to change the - * value that is returned by the actual function invocation. - * - */ - this.invokeFun = function (iid, f, base, args, result, isConstructor, isMethod, functionIid, functionSid) { - return {result: result}; - }; - - /** - * This callback is called after the creation of a literal. A literal can be a function literal, an object literal, - * an array literal, a number, a string, a boolean, a regular expression, null, NaN, Infinity, or undefined. - * - * @example - * x = "Hello" - * - * // the above call roughly gets instrumented as follows: - * - * var result = "Hello"; - * var aret = analysis.literal(201, result, false); - * if (aret) { - * result = aret.result; - * } - * x = result; - * - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} val - The literal value - * @param {boolean} hasGetterSetter - True if the literal is an object and the object defines getters and setters - * @returns {{result: *} | undefined} - If the function returns an object, then the original literal value is - * replaced with the value stored in the result property of the object. - * - */ - this.literal = function (iid, val, hasGetterSetter) { - return {result: val}; - }; - - /** - * This callback is called when a for-in loop is used to iterate the properties of an object. - * - *@example - * for (x in y) { } - * - * // the above call roughly gets instrumented as follows: - * - * var aret = analysis.forinObject(iid, y); - * if (aret) { - * y = aret.result; - * } - * for (x in y) {} - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} val - Objects whose properties are iterated in a for-in loop. - * @returns {{result: *} | undefined} - If the function returns an object, then the original object whose - * properties are being iterated is replaced with the value stored in the result property of the - * returned object. - * - */ - this.forinObject = function (iid, val) { - return {result: val}; - }; - - /** - * This callback is triggered at the beginning of a scope for every local variable declared in the scope, for - * every formal parameter, for every function defined using a function statement, for arguments - * variable, and for the formal parameter passed in a catch statement. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} name - Name of the variable that is declared - * @param {*} val - Initial value of the variable that is declared. Variables can be local variables, function - * parameters, catch parameters, arguments, or functions defined using function statements. Variables - * declared with var have undefined as initial values and cannot be changed by returning a - * different value from this callback. On the beginning of an execution of a function, a declare - * callback is called on the arguments variable. - * @param {boolean} isArgument - True if the variable is arguments or a formal parameter. - * @param {number} argumentIndex - Index of the argument in the function call. Indices start from 0. If the - * variable is not a formal parameter, then argumentIndex is -1. - * @param {boolean} isCatchParam - True if the variable is a parameter of a catch statement. - * @returns {{result: *} | undefined} - If the function returns an object, then the original initial value is - * replaced with the value stored in the result property of the object. This does not apply to local - * variables declared with var. - * - */ - this.declare = function (iid, name, val, isArgument, argumentIndex, isCatchParam) { - return {result: val}; - }; - - /** - * This callback is called before a property of an object is accessed. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} base - Base object - * @param {string|*} offset - Property - * @param {boolean} isComputed - True if property is accessed using square brackets. For example, - * isComputed is true if the get field operation is o[p], and false - * if the get field operation is o.p - * @param {boolean} isOpAssign - True if the operation is of the formo.p op= e
- * @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. o.p())
- * @returns {{base: *, offset: *, skip: boolean} | undefined} - If an object is returned and the skip
- * property of the object is true, then the get field operation is skipped. Original base and
- * offset are replaced with that from the returned object if an object is returned.
- *
- */
- this.getFieldPre = function (iid, base, offset, isComputed, isOpAssign, isMethodCall) {
- return {base: base, offset: offset, skip: false};
- };
-
- /**
- * This callback is called after a property of an object is accessed.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} base - Base object
- * @param {string|*} offset - Property
- * @param {*} val - Value of base[offset]
- * @param {boolean} isComputed - True if property is accessed using square brackets. For example,
- * isComputed is true if the get field operation is o[p], and false
- * if the get field operation is o.p
- * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e
- * @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. o.p())
- * @returns {{result: *} | undefined} - If an object is returned, the value of the get field operation is
- * replaced with the value stored in the result property of the object.
- */
- this.getField = function (iid, base, offset, val, isComputed, isOpAssign, isMethodCall) {
- return {result: val};
- };
-
- /**
- * This callback is called before a property of an object is written.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} base - Base object
- * @param {*} offset - Property
- * @param {*} val - Value to be stored in base[offset]
- * @param {boolean} isComputed - True if property is accessed using square brackets. For example,
- * isComputed is true if the get field operation is o[p], and false
- * if the get field operation is o.p
- * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e
- * @returns {{base: *, offset: *, val: *, skip: boolean} | undefined} - If an object is returned and the skip
- * property is true, then the put field operation is skipped. Original base, offset, and
- * val are replaced with that from the returned object if an object is returned.
- */
- this.putFieldPre = function (iid, base, offset, val, isComputed, isOpAssign) {
- return {base: base, offset: offset, val: val, skip: false};
- };
-
- /**
- * This callback is called after a property of an object is written.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} base - Base object
- * @param {*} offset - Property
- * @param {*} val - Value to be stored in base[offset]
- * @param {boolean} isComputed - True if property is accessed using square brackets. For example,
- * isComputed is true if the get field operation is o[p], and false
- * if the get field operation is o.p
- * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e
- * @returns {{result: *} | undefined} - If an object is returned, the result of the put field operation is
- * replaced with the value stored in the result property of the object.
- */
- this.putField = function (iid, base, offset, val, isComputed, isOpAssign) {
- return {result: val};
- };
-
- /**
- * This callback is called after a variable is read.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {string} name - Name of the variable being read
- * @param {*} val - Value read from the variable
- * @param {boolean} isGlobal - True if the variable is not declared using var (e.g. console)
- * @param {boolean} isScriptLocal - True if the variable is declared in the global scope using var
- * @returns {{result: *} | undefined} - If an object is returned, the result of the read operation is
- * replaced with the value stored in the result property of the object.
- */
- this.read = function (iid, name, val, isGlobal, isScriptLocal) {
- return {result: val};
- };
-
- /**
- * This callback is called before a variable is written.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {string} name - Name of the variable being read
- * @param {*} val - Value to be written to the variable
- * @param {*} lhs - Value stored in the variable before the write operation
- * @param {boolean} isGlobal - True if the variable is not declared using var (e.g. console)
- * @param {boolean} isScriptLocal - True if the variable is declared in the global scope using var
- * @returns {{result: *} | undefined} - If an object is returned, the result of the write operation is
- * replaced with the value stored in the result property of the object.
- */
- this.write = function (iid, name, val, lhs, isGlobal, isScriptLocal) {
- return {result: val};
- };
-
- /**
- * This callback is called before a value is returned from a function using the return keyword.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} val - Value to be returned
- * @returns {{result: *} | undefined} - If an object is returned, the value to be returned is
- * replaced with the value stored in the result property of the object.
- */
- this._return = function (iid, val) {
- return {result: val};
- };
-
- /**
- * This callback is called before a value is thrown using the throw keyword.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} val - Value to be thrown
- * @returns {{result: *} | undefined} - If an object is returned, the value to be thrown is
- * replaced with the value stored in the result property of the object.
- */
- this._throw = function (iid, val) {
- return {result: val};
- };
-
- /**
- * This callback is called when a with statement is executed
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} val - Value used as an argument to with
- * @returns {{result: *} | undefined} - If an object is returned, the value to be used in with is
- * replaced with the value stored in the result property of the object.
- */
- this._with = function (iid, val) {
- return {result: val};
- };
-
- /**
- * This callback is called before the execution of a function body starts.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {function} f - The function object whose body is about to get executed
- * @param {*} dis - The value of the this variable in the function body
- * @param {Array} args - List of the arguments with which the function is called
- * @returns {undefined} - Any return value is ignored
- */
- this.functionEnter = function (iid, f, dis, args) {
- };
-
- /**
- * This callback is called when the execution of a function body completes
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} returnVal - The value returned by the function
- * @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the function
- * execution has thrown an uncaught exception and the exception is being stored in the exception
- * property of the parameter
- * @returns {{returnVal: *, wrappedExceptionVal: *, isBacktrack: boolean}} If an object is returned, then the
- * actual returnVal and wrappedExceptionVal.exception are replaced with that from the
- * returned object. If an object is returned and the property isBacktrack is set, then the control-flow
- * returns to the beginning of the function body instead of returning to the caller. The property
- * isBacktrack can be set to true to repeatedly execute the function body as in MultiSE
- * symbolic execution.
- */
- this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
- return {returnVal: returnVal, wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false};
- };
-
- /**
- * This callback is called before the execution of a JavaScript file
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {string} instrumentedFileName - Name of the instrumented script file
- * @param {string} originalFileName - Name of the original script file
- */
- this.scriptEnter = function (iid, instrumentedFileName, originalFileName) {
- };
-
- /**
- * This callback is called when the execution of a JavaScript file completes
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the script
- * execution has thrown an uncaught exception and the exception is being stored in the exception
- * property of the parameter
- * @returns {{wrappedExceptionVal: *, isBacktrack: boolean}} - If an object is returned, then the
- * actual wrappedExceptionVal.exception is replaced with that from the
- * returned object. If an object is returned and the property isBacktrack is set, then the control-flow
- * returns to the beginning of the script body. The property
- * isBacktrack can be set to true to repeatedly execute the script body as in MultiSE
- * symbolic execution.
- */
- this.scriptExit = function (iid, wrappedExceptionVal) {
- return {wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false};
- };
-
- /**
- * This callback is called before a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
- * <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in. No callback for delete x
- * because this operation cannot be performed reflectively.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {string} op - Operation to be performed
- * @param {*} left - Left operand
- * @param {*} right - Right operand
- * @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form
- * x op= e
- * @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant
- * with a consequent in a switch statement.
- * @param {boolean} isComputed - True if the operation is of the form delete x[p]
, and false
- * otherwise (even if the operation if of the form delete x.p
)
- * @returns {{op: string, left: *, right: *, skip: boolean}|undefined} - If an object is returned and the
- * skip property is true, then the binary operation is skipped. Original op, left,
- * and right are replaced with that from the returned object if an object is returned.
- */
- this.binaryPre = function (iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed) {
- return {op: op, left: left, right: right, skip: false};
- };
-
- /**
- * This callback is called after a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
- * <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {string} op - Operation to be performed
- * @param {*} left - Left operand
- * @param {*} right - Right operand
- * @param {*} result - The result of the binary operation
- * @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form
- * x op= e
- * @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant
- * with a consequent in a switch statement.
- * @param {boolean} isComputed - True if the operation is of the form delete x[p]
, and false
- * otherwise (even if the operation if of the form delete x.p
)
- * @returns {{result: *}|undefined} - If an object is returned, the result of the binary operation is
- * replaced with the value stored in the result property of the object.
- */
- this.binary = function (iid, op, left, right, result, isOpAssign, isSwitchCaseComparison, isComputed) {
- return {result: result};
- };
-
- /**
- * This callback is called before a unary operation. Unary operations include +, -, ~, !, typeof, void.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {string} op - Operation to be performed
- * @param {*} left - Left operand
- * @returns {{op: *, left: *, skip: boolean} | undefined} If an object is returned and the
- * skip property is true, then the unary operation is skipped. Original op and left
- * are replaced with that from the returned object if an object is returned.
- */
- this.unaryPre = function (iid, op, left) {
- return {op: op, left: left, skip: false};
- };
-
- /**
- * This callback is called after a unary operation. Unary operations include +, -, ~, !, typeof, void.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {string} op - Operation to be performed
- * @param {*} left - Left operand
- * @param {*} result - The result of the unary operation
- * @returns {{result: *}|undefined} - If an object is returned, the result of the unary operation is
- * replaced with the value stored in the result property of the object.
- *
- */
- this.unary = function (iid, op, left, result) {
- return {result: result};
- };
-
- /**
- * This callback is called after a condition check before branching. Branching can happen in various statements
- * including if-then-else, switch-case, while, for, ||, &&, ?:.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} result - The value of the conditional expression
- * @returns {{result: *}|undefined} - If an object is returned, the result of the conditional expression is
- * replaced with the value stored in the result property of the object.
- */
- this.conditional = function (iid, result) {
- return {result: result};
- };
-
- /**
- * This callback is called before a string passed as an argument to eval or Function is instrumented.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} code - Code that is going to get instrumented
- * @param {boolean} isDirect - true if this is a direct call to eval
- * @returns {{code: *, skip: boolean}} - If an object is returned and the
- * skip property is true, then the instrumentation of code is skipped.
- * Original code is replaced with that from the returned object if an object is returned.
- */
- this.instrumentCodePre = function (iid, code, isDirect) {
- return {code: code, skip: false};
- };
-
- /**
- * This callback is called after a string passed as an argument to eval or Function is instrumented.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {*} newCode - Instrumented code
- * @param {Object} newAst - The AST of the instrumented code
- * @param {boolean} isDirect - true if this is a direct call to eval
- * @returns {{result: *}|undefined} - If an object is returned, the instrumented code is
- * replaced with the value stored in the result property of the object.
- */
- this.instrumentCode = function (iid, newCode, newAst, isDirect) {
- return {result: newCode};
- };
-
- /**
- * This callback is called when an expression is evaluated and its value is discarded. For example, this
- * callback is called when an expression statement completes its execution.
- *
- * @param {number} iid - Static unique instruction identifier of this callback
- * @returns {undefined} - Any return value is ignored
- */
- this.endExpression = function (iid) {
- };
-
- /**
- * This callback is called when an execution terminates in node.js. In a browser environment, the callback is
- * called if ChainedAnalyses.js or ChainedAnalysesNoCheck.js is used and Alt-Shift-T is pressed.
- *
- * @returns {undefined} - Any return value is ignored
- */
- this.endExecution = function () {
- };
-
- /**
- * This callback is called only when instrumented with J$.Config.ENABLE_SAMPLING = true
- * This callback is called before the body of a function, method, or constructor is executed
- * if returns true, instrumented function body is executed, else uninstrumented function body is executed
- * @param {number} iid - Static unique instruction identifier of this callback
- * @param {function} f - The function whose body is being executed
- * @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created
- * @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created
- * {@link MyAnalysis#functionEnter} when the function f is executed. The functionIid can be
- * treated as the static identifier of the function f. Note that a given function code block can
- * create several function objects, but each such object has a common functionIid, which is the iid
- * that is passed to {@link MyAnalysis#functionEnter} when the function executes.
- * @returns {boolean} - If true is returned the instrumented function body is executed, otherwise the
- * uninstrumented function body is executed.
- */
- this.runInstrumentedFunctionBody = function (iid, f, functionIid, functionSid) {
- return false;
- };
-
- /**
- * onReady is useful if your analysis is running on node.js (i.e., via the direct.js or jalangi.js commands)
- * and needs to complete some asynchronous initialization before the instrumented program starts. In such a
- * case, once the initialization is complete, invoke the cb function to start execution of the instrumented
- * program.
- *
- * Note that this callback is not useful in the browser, as Jalangi has no control over when the
- * instrumented program runs there.
- * @param cb
- */
- this.onReady = function (cb) {
- cb();
- };
- }
-
- sandbox.analysis = new MyAnalysis();
-})(J$);
-
-
-
diff --git a/src_bundle/index.mjs b/src_bundle/index.mjs
index 85ed611..608b91c 100644
--- a/src_bundle/index.mjs
+++ b/src_bundle/index.mjs
@@ -2,25 +2,39 @@ import wp from 'webpack';
import path from 'node:path'
const outputPath = path.resolve('./output/');
console.log(outputPath);
+
+const l = 'classnames'
+const libraryLocation = import.meta.resolve(l);
+console.log(libraryLocation);
+
+
+// throw Error("5");
const compiler = wp({
- entry:'./test_src/arithmetic.cjs',
+ entry:libraryLocation,
mode: 'production',
optimization:{
mangleExports: false,
avoidEntryIife: true,
minimize: false
+
},
+ // experiments:{}
output: {
path: outputPath,
- filename: 'lodash.bundle.js',
- scriptType: 'module',
-
+ filename: l+'.bundle.cjs',
+ clean: true,
+ iife: false,
+ library: {
+ type: 'commonjs2',
+ // name: l
+ }
+ // module: true
}
,
},(err,stats)=>{
if (err || stats.hasErrors()) {
- console.log(stats.hasErrors())
console.log(err?.stack)
- console.log(stats.toJson());
+ console.log(stats?.hasErrors())
+ console.log(stats?.toJson());
}
})
diff --git a/test_src/arithmetic.cjs b/test_src/arithmetic.cjs
index 3ce8f5f..944cbaa 100644
--- a/test_src/arithmetic.cjs
+++ b/test_src/arithmetic.cjs
@@ -1,4 +1,10 @@
module.exports.sum = function sum(a, b) {
+ let x = 0;
+
+ for(var c in [1,2,3,4]){
+ x+=c;
+ }
+
return a + b;
}
module.exports.div = function div(a, b) {
diff --git a/test_src/classnames.bundle.cjs b/test_src/classnames.bundle.cjs
new file mode 100644
index 0000000..7002fa7
--- /dev/null
+++ b/test_src/classnames.bundle.cjs
@@ -0,0 +1,120 @@
+/******/ var __webpack_modules__ = ({
+
+/***/ 485:
+/***/ ((module, exports) => {
+
+var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
+ Copyright (c) 2018 Jed Watson.
+ Licensed under the MIT License (MIT), see
+ http://jedwatson.github.io/classnames
+*/
+/* global define */
+
+(function () {
+ 'use strict';
+
+ var hasOwn = {}.hasOwnProperty;
+
+ function classNames () {
+ var classes = '';
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ if (arg) {
+ classes = appendClass(classes, parseValue(arg));
+ }
+ }
+
+ return classes;
+ }
+
+ function parseValue (arg) {
+ if (typeof arg === 'string' || typeof arg === 'number') {
+ return arg;
+ }
+
+ if (typeof arg !== 'object') {
+ return '';
+ }
+
+ if (Array.isArray(arg)) {
+ return classNames.apply(null, arg);
+ }
+
+ if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {
+ return arg.toString();
+ }
+
+ var classes = '';
+
+ for (var key in arg) {
+ if (hasOwn.call(arg, key) && arg[key]) {
+ classes = appendClass(classes, key);
+ }
+ }
+
+ return classes;
+ }
+
+ function appendClass (value, newClass) {
+ if (!newClass) {
+ return value;
+ }
+
+ if (value) {
+ return value + ' ' + newClass;
+ }
+
+ return value + newClass;
+ }
+
+ if ( true && module.exports) {
+ classNames.default = classNames;
+ module.exports = classNames;
+ } else if (true) {
+ // register as 'classnames', consistent with npm package name
+ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function () {
+ return classNames;
+ }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
+ __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+ } else // removed by dead control flow
+{}
+}());
+
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/
+/******/ // startup
+/******/ // Load entry module and return exports
+/******/ // This entry module is referenced by other modules so it can't be inlined
+/******/ var __webpack_exports__ = __webpack_require__(485);
+/******/ module.exports = __webpack_exports__;
+/******/
diff --git a/test_src/index.cjs b/test_src/index.cjs
index 08679e5..97f0ea6 100644
--- a/test_src/index.cjs
+++ b/test_src/index.cjs
@@ -1,9 +1,10 @@
var {existsSync,readFile} = require('node:fs');
// const {cwd} = require('process');
var _var = require('process');
-var {sum, div} = require('./arithmetic.cjs');
-var {sum, div} = require('../output/lodash.bundle.js');
-var {ceil} = require('./lodash.js')
+var {sum, div,sad} = require('./arithmetic.cjs');
+// var {sum, div} = require('../output/lodash.bundle.js');
+// var {ceil} = require('./lodash.js')
+var cn = require('./classnames.bundle.cjs')
let cwd = process.cwd;
console.log('a')
@@ -20,5 +21,6 @@ console.log(`Read some data`,newLocal,sum(2,34));
console.log(`Read some data`,newLocal,
div(7,0),
div(32,3),
- ceil(10.24)
+ // ceil(10.24),
+ cn('fooo','foobar')
);
\ No newline at end of file
diff --git a/todo b/todo
index 16d4d85..9ca9db5 100644
--- a/todo
+++ b/todo
@@ -1,2 +1,14 @@
Handle aliasing as a important piece in draft
Please note down problem exploration
+
+
+
+
+
+
+###
+My single lib analysis.
+
+
+- [ ] Scan a library. Get its dependencies.
+- [ ] Call for its dependencies. Proxy it.
\ No newline at end of file