From 5b584a90a5a890ec4417788bdc142bf6dedf665d Mon Sep 17 00:00:00 2001 From: Atreya Bain Date: Mon, 21 Jul 2025 17:01:43 +0100 Subject: [PATCH] [add] code --- .gitignore | 1 + package-lock.json | 10 +- package.json | 3 +- src/index.mjs | 78 +-- src_analysis/analysisCallbackTemplate.cjs | 647 ---------------------- src_bundle/index.mjs | 26 +- test_src/arithmetic.cjs | 6 + test_src/classnames.bundle.cjs | 120 ++++ test_src/index.cjs | 10 +- todo | 12 + 10 files changed, 215 insertions(+), 698 deletions(-) delete mode 100644 src_analysis/analysisCallbackTemplate.cjs create mode 100644 test_src/classnames.bundle.cjs 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 form o.p op= e - * @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. o.p()) - * @returns {{base: *, offset: *, skip: boolean} | undefined} - If an object is returned and the skip - * property of the object is true, then the get field operation is skipped. Original base and - * offset are replaced with that from the returned object if an object is returned. - * - */ - this.getFieldPre = function (iid, base, offset, isComputed, isOpAssign, isMethodCall) { - return {base: base, offset: offset, skip: false}; - }; - - /** - * This callback is called after a property of an object is accessed. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} base - Base object - * @param {string|*} offset - Property - * @param {*} val - Value of base[offset] - * @param {boolean} isComputed - True if property is accessed using square brackets. For example, - * isComputed is true if the get field operation is o[p], and false - * if the get field operation is o.p - * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e - * @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. o.p()) - * @returns {{result: *} | undefined} - If an object is returned, the value of the get field operation is - * replaced with the value stored in the result property of the object. - */ - this.getField = function (iid, base, offset, val, isComputed, isOpAssign, isMethodCall) { - return {result: val}; - }; - - /** - * This callback is called before a property of an object is written. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} base - Base object - * @param {*} offset - Property - * @param {*} val - Value to be stored in base[offset] - * @param {boolean} isComputed - True if property is accessed using square brackets. For example, - * isComputed is true if the get field operation is o[p], and false - * if the get field operation is o.p - * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e - * @returns {{base: *, offset: *, val: *, skip: boolean} | undefined} - If an object is returned and the skip - * property is true, then the put field operation is skipped. Original base, offset, and - * val are replaced with that from the returned object if an object is returned. - */ - this.putFieldPre = function (iid, base, offset, val, isComputed, isOpAssign) { - return {base: base, offset: offset, val: val, skip: false}; - }; - - /** - * This callback is called after a property of an object is written. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} base - Base object - * @param {*} offset - Property - * @param {*} val - Value to be stored in base[offset] - * @param {boolean} isComputed - True if property is accessed using square brackets. For example, - * isComputed is true if the get field operation is o[p], and false - * if the get field operation is o.p - * @param {boolean} isOpAssign - True if the operation is of the form o.p op= e - * @returns {{result: *} | undefined} - If an object is returned, the result of the put field operation is - * replaced with the value stored in the result property of the object. - */ - this.putField = function (iid, base, offset, val, isComputed, isOpAssign) { - return {result: val}; - }; - - /** - * This callback is called after a variable is read. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} name - Name of the variable being read - * @param {*} val - Value read from the variable - * @param {boolean} isGlobal - True if the variable is not declared using var (e.g. console) - * @param {boolean} isScriptLocal - True if the variable is declared in the global scope using var - * @returns {{result: *} | undefined} - If an object is returned, the result of the read operation is - * replaced with the value stored in the result property of the object. - */ - this.read = function (iid, name, val, isGlobal, isScriptLocal) { - return {result: val}; - }; - - /** - * This callback is called before a variable is written. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} name - Name of the variable being read - * @param {*} val - Value to be written to the variable - * @param {*} lhs - Value stored in the variable before the write operation - * @param {boolean} isGlobal - True if the variable is not declared using var (e.g. console) - * @param {boolean} isScriptLocal - True if the variable is declared in the global scope using var - * @returns {{result: *} | undefined} - If an object is returned, the result of the write operation is - * replaced with the value stored in the result property of the object. - */ - this.write = function (iid, name, val, lhs, isGlobal, isScriptLocal) { - return {result: val}; - }; - - /** - * This callback is called before a value is returned from a function using the return keyword. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} val - Value to be returned - * @returns {{result: *} | undefined} - If an object is returned, the value to be returned is - * replaced with the value stored in the result property of the object. - */ - this._return = function (iid, val) { - return {result: val}; - }; - - /** - * This callback is called before a value is thrown using the throw keyword. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} val - Value to be thrown - * @returns {{result: *} | undefined} - If an object is returned, the value to be thrown is - * replaced with the value stored in the result property of the object. - */ - this._throw = function (iid, val) { - return {result: val}; - }; - - /** - * This callback is called when a with statement is executed - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} val - Value used as an argument to with - * @returns {{result: *} | undefined} - If an object is returned, the value to be used in with is - * replaced with the value stored in the result property of the object. - */ - this._with = function (iid, val) { - return {result: val}; - }; - - /** - * This callback is called before the execution of a function body starts. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {function} f - The function object whose body is about to get executed - * @param {*} dis - The value of the this variable in the function body - * @param {Array} args - List of the arguments with which the function is called - * @returns {undefined} - Any return value is ignored - */ - this.functionEnter = function (iid, f, dis, args) { - }; - - /** - * This callback is called when the execution of a function body completes - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} returnVal - The value returned by the function - * @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the function - * execution has thrown an uncaught exception and the exception is being stored in the exception - * property of the parameter - * @returns {{returnVal: *, wrappedExceptionVal: *, isBacktrack: boolean}} If an object is returned, then the - * actual returnVal and wrappedExceptionVal.exception are replaced with that from the - * returned object. If an object is returned and the property isBacktrack is set, then the control-flow - * returns to the beginning of the function body instead of returning to the caller. The property - * isBacktrack can be set to true to repeatedly execute the function body as in MultiSE - * symbolic execution. - */ - this.functionExit = function (iid, returnVal, wrappedExceptionVal) { - return {returnVal: returnVal, wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false}; - }; - - /** - * This callback is called before the execution of a JavaScript file - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} instrumentedFileName - Name of the instrumented script file - * @param {string} originalFileName - Name of the original script file - */ - this.scriptEnter = function (iid, instrumentedFileName, originalFileName) { - }; - - /** - * This callback is called when the execution of a JavaScript file completes - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the script - * execution has thrown an uncaught exception and the exception is being stored in the exception - * property of the parameter - * @returns {{wrappedExceptionVal: *, isBacktrack: boolean}} - If an object is returned, then the - * actual wrappedExceptionVal.exception is replaced with that from the - * returned object. If an object is returned and the property isBacktrack is set, then the control-flow - * returns to the beginning of the script body. The property - * isBacktrack can be set to true to repeatedly execute the script body as in MultiSE - * symbolic execution. - */ - this.scriptExit = function (iid, wrappedExceptionVal) { - return {wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false}; - }; - - /** - * This callback is called before a binary operation. Binary operations include +, -, *, /, %, &, |, ^, - * <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in. No callback for delete x - * because this operation cannot be performed reflectively. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} op - Operation to be performed - * @param {*} left - Left operand - * @param {*} right - Right operand - * @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form - * x op= e - * @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant - * with a consequent in a switch statement. - * @param {boolean} isComputed - True if the operation is of the form delete x[p], and false - * otherwise (even if the operation if of the form delete x.p) - * @returns {{op: string, left: *, right: *, skip: boolean}|undefined} - If an object is returned and the - * skip property is true, then the binary operation is skipped. Original op, left, - * and right are replaced with that from the returned object if an object is returned. - */ - this.binaryPre = function (iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed) { - return {op: op, left: left, right: right, skip: false}; - }; - - /** - * This callback is called after a binary operation. Binary operations include +, -, *, /, %, &, |, ^, - * <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} op - Operation to be performed - * @param {*} left - Left operand - * @param {*} right - Right operand - * @param {*} result - The result of the binary operation - * @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form - * x op= e - * @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant - * with a consequent in a switch statement. - * @param {boolean} isComputed - True if the operation is of the form delete x[p], and false - * otherwise (even if the operation if of the form delete x.p) - * @returns {{result: *}|undefined} - If an object is returned, the result of the binary operation is - * replaced with the value stored in the result property of the object. - */ - this.binary = function (iid, op, left, right, result, isOpAssign, isSwitchCaseComparison, isComputed) { - return {result: result}; - }; - - /** - * This callback is called before a unary operation. Unary operations include +, -, ~, !, typeof, void. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} op - Operation to be performed - * @param {*} left - Left operand - * @returns {{op: *, left: *, skip: boolean} | undefined} If an object is returned and the - * skip property is true, then the unary operation is skipped. Original op and left - * are replaced with that from the returned object if an object is returned. - */ - this.unaryPre = function (iid, op, left) { - return {op: op, left: left, skip: false}; - }; - - /** - * This callback is called after a unary operation. Unary operations include +, -, ~, !, typeof, void. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {string} op - Operation to be performed - * @param {*} left - Left operand - * @param {*} result - The result of the unary operation - * @returns {{result: *}|undefined} - If an object is returned, the result of the unary operation is - * replaced with the value stored in the result property of the object. - * - */ - this.unary = function (iid, op, left, result) { - return {result: result}; - }; - - /** - * This callback is called after a condition check before branching. Branching can happen in various statements - * including if-then-else, switch-case, while, for, ||, &&, ?:. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} result - The value of the conditional expression - * @returns {{result: *}|undefined} - If an object is returned, the result of the conditional expression is - * replaced with the value stored in the result property of the object. - */ - this.conditional = function (iid, result) { - return {result: result}; - }; - - /** - * This callback is called before a string passed as an argument to eval or Function is instrumented. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} code - Code that is going to get instrumented - * @param {boolean} isDirect - true if this is a direct call to eval - * @returns {{code: *, skip: boolean}} - If an object is returned and the - * skip property is true, then the instrumentation of code is skipped. - * Original code is replaced with that from the returned object if an object is returned. - */ - this.instrumentCodePre = function (iid, code, isDirect) { - return {code: code, skip: false}; - }; - - /** - * This callback is called after a string passed as an argument to eval or Function is instrumented. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @param {*} newCode - Instrumented code - * @param {Object} newAst - The AST of the instrumented code - * @param {boolean} isDirect - true if this is a direct call to eval - * @returns {{result: *}|undefined} - If an object is returned, the instrumented code is - * replaced with the value stored in the result property of the object. - */ - this.instrumentCode = function (iid, newCode, newAst, isDirect) { - return {result: newCode}; - }; - - /** - * This callback is called when an expression is evaluated and its value is discarded. For example, this - * callback is called when an expression statement completes its execution. - * - * @param {number} iid - Static unique instruction identifier of this callback - * @returns {undefined} - Any return value is ignored - */ - this.endExpression = function (iid) { - }; - - /** - * This callback is called when an execution terminates in node.js. In a browser environment, the callback is - * called if ChainedAnalyses.js or ChainedAnalysesNoCheck.js is used and Alt-Shift-T is pressed. - * - * @returns {undefined} - Any return value is ignored - */ - this.endExecution = function () { - }; - - /** - * This callback is called only when instrumented with J$.Config.ENABLE_SAMPLING = true - * This callback is called before the body of a function, method, or constructor is executed - * if returns true, instrumented function body is executed, else uninstrumented function body is executed - * @param {number} iid - Static unique instruction identifier of this callback - * @param {function} f - The function whose body is being executed - * @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created - * @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created - * {@link MyAnalysis#functionEnter} when the function f is executed. The functionIid can be - * treated as the static identifier of the function f. Note that a given function code block can - * create several function objects, but each such object has a common functionIid, which is the iid - * that is passed to {@link MyAnalysis#functionEnter} when the function executes. - * @returns {boolean} - If true is returned the instrumented function body is executed, otherwise the - * uninstrumented function body is executed. - */ - this.runInstrumentedFunctionBody = function (iid, f, functionIid, functionSid) { - return false; - }; - - /** - * onReady is useful if your analysis is running on node.js (i.e., via the direct.js or jalangi.js commands) - * and needs to complete some asynchronous initialization before the instrumented program starts. In such a - * case, once the initialization is complete, invoke the cb function to start execution of the instrumented - * program. - * - * Note that this callback is not useful in the browser, as Jalangi has no control over when the - * instrumented program runs there. - * @param cb - */ - this.onReady = function (cb) { - cb(); - }; - } - - sandbox.analysis = new MyAnalysis(); -})(J$); - - - diff --git a/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