JavaScript: Use type tracking to identify more portal entry/exit nodes.

This commit is contained in:
Ellen Arteca
2019-07-05 04:03:37 -04:00
committed by Max Schaefer
parent 9bf0a3f2cd
commit 39c37f519d
6 changed files with 98 additions and 10 deletions

View File

@@ -115,6 +115,37 @@ class Portal extends TPortal {
abstract int depth();
}
/**
* Gets an exit node for the specified portal, using TypeTracking.
*
* Called in instances where an exit node is computed from another exit node
* (for example, in MemberPortal's portalBaseRef predicate).
*/
private DataFlow::SourceNode trackExitNode(
Portal base, boolean isRemote, DataFlow::TypeTracker t
) {
t.start() and
result = base.getAnExitNode(isRemote)
or
exists(DataFlow::TypeTracker t2 | result = trackExitNode(base, isRemote, t2).track(t2, t))
}
/**
* Gets an entry node for the specified portal, using TypeBackTracking.
*
* Parallel to trackExitNode above.
*/
private DataFlow::SourceNode trackEntryNode(
Portal base, boolean escapes, DataFlow::TypeBackTracker t
) {
t.start() and
result = base.getAnEntryNode(escapes).getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 |
result = trackEntryNode(base, escapes, t2).backtrack(t2, t)
)
}
/**
* A portal representing the exports value of the main module of an npm
* package (that is, a value of `module.exports` for CommonJS modules, or
@@ -260,9 +291,9 @@ private class MemberPortal extends CompoundPortal, MkMemberPortal {
private module MemberPortal {
/** Gets a node representing a value flowing through `base`, that is, either an entry node or an exit node. */
private DataFlow::SourceNode portalBaseRef(Portal base, boolean escapes) {
result = base.getAnExitNode(escapes)
result = trackExitNode(base, escapes, DataFlow::TypeTracker::end())
or
result = base.getAnEntryNode(escapes).getALocalSource()
result = trackEntryNode(base, escapes, DataFlow::TypeBackTracker::end())
}
/** Holds if `read` is a read of property `prop` of a value flowing through `base`. */
@@ -342,13 +373,13 @@ private module InstancePortal {
Portal base, DataFlow::SourceNode ctor, AbstractInstance i, boolean escapes
) {
ctor = DataFlow::valueNode(i.getConstructor().getDefinition()) and
ctor.flowsTo(base.getAnEntryNode(escapes)) and
ctor = trackEntryNode(base, escapes, DataFlow::TypeBackTracker::end()) and
instantiable(ctor)
}
/** Holds if `nd` is an expression evaluating to an instance of `base`. */
predicate instanceUse(Portal base, DataFlow::SourceNode nd, boolean isRemote) {
nd = base.getAnExitNode(isRemote).getAnInstantiation()
nd = trackExitNode(base, isRemote, DataFlow::TypeTracker::end()).getAnInstantiation()
or
isInstance(base, _, nd.analyze().getAValue(), isRemote)
}
@@ -415,13 +446,14 @@ class ParameterPortal extends CompoundPortal, MkParameterPortal {
private module ParameterPortal {
/** Holds if `param` is the `i`th parameter of a function flowing through `base`. */
predicate parameter(Portal base, int i, DataFlow::SourceNode param, boolean isRemote) {
param = base.getAnEntryNode(isRemote).getALocalSource().(DataFlow::FunctionNode).getParameter(i)
param = trackEntryNode(base, isRemote, DataFlow::TypeBackTracker::end()).(DataFlow::FunctionNode)
.getParameter(i)
}
/** Holds if `arg` is the `i`th argument passed to an invocation of a function flowing through `base`. */
predicate argument(Portal base, int i, DataFlow::Node arg, boolean escapes) {
exists(DataFlow::InvokeNode invk |
invk = base.getAnExitNode(escapes).getAnInvocation() and
invk = trackExitNode(base, escapes, DataFlow::TypeTracker::end()).getAnInvocation() and
arg = invk.getArgument(i)
)
}
@@ -449,11 +481,14 @@ class ReturnPortal extends CompoundPortal, MkReturnPortal {
private module ReturnPortal {
/** Holds if `invk` is a call to a function flowing through `callee`. */
predicate calls(DataFlow::InvokeNode invk, Portal callee, boolean isRemote) {
invk = callee.getAnExitNode(isRemote).getAnInvocation()
invk = trackExitNode(callee, isRemote, DataFlow::TypeTracker::end())
.getAnInvocation()
}
/** Holds if `ret` is a return node of a function flowing through `callee`. */
predicate returns(Portal base, DataFlow::Node ret, boolean escapes) {
ret = base.getAnEntryNode(escapes).getALocalSource().(DataFlow::FunctionNode).getAReturn()
ret = trackEntryNode(base, escapes, DataFlow::TypeBackTracker::end())
.(DataFlow::FunctionNode)
.getAReturn()
}
}

View File

@@ -1,5 +1,9 @@
| (member NP (root https://www.npmjs.com/package/typeTracking)) | src/typeTracking/index.js:20:14:20:15 | NP | true |
| (member Promise (root https://www.npmjs.com/package/bluebird)) | src/bluebird/index.js:9:19:9:25 | Promise | true |
| (member argFunc (instance (member NP (root https://www.npmjs.com/package/typeTracking)))) | src/typeTracking/index.js:16:24:18:1 | functio ... ck();\\n} | true |
| (member createNP (instance (member NP (root https://www.npmjs.com/package/typeTracking)))) | src/typeTracking/index.js:12:25:14:1 | functio ... bj();\\n} | true |
| (member default (root https://www.npmjs.com/package/m2)) | src/m2/main.js:6:16:16:1 | class { ... y; }\\n} | true |
| (member exec (instance (member NP (root https://www.npmjs.com/package/typeTracking)))) | src/typeTracking/index.js:2:14:2:17 | exec | true |
| (member exec (instance (member Promise (root https://www.npmjs.com/package/bluebird)))) | src/bluebird/index.js:2:15:2:18 | exec | true |
| (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:5:11:5:13 | foo | true |
| (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic))))))))) | src/cyclic/index.js:5:11:5:13 | foo | true |
@@ -1014,6 +1018,7 @@
| (parameter 0 (root https://www.npmjs.com/package/m1)) | src/m3/index.js:3:46:3:60 | "Hello, world!" | false |
| (parameter 0 (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:4:7:4:10 | "me" | false |
| (parameter 0 (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:5:7:5:10 | "me" | false |
| (return (member createNP (instance (member NP (root https://www.npmjs.com/package/typeTracking))))) | src/typeTracking/index.js:13:9:13:21 | new tempObj() | true |
| (return (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:3:10:3:12 | foo | true |
| (return (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic))))))))) | src/cyclic/index.js:3:10:3:12 | foo | true |
| (return (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (return (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:3:10:3:12 | foo | true |
@@ -1712,4 +1717,4 @@
| (return (return (return (return (return (return (return (member foo (root https://www.npmjs.com/package/cyclic))))))))) | src/cyclic/index.js:3:10:3:12 | foo | true |
| (return (return (return (return (return (return (return (return (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:3:10:3:12 | foo | true |
| (return (root https://www.npmjs.com/package/m1)) | src/m1/index.js:1:25:1:25 | x | true |
| (root https://www.npmjs.com/package/m1) | src/m1/index.js:1:18:1:25 | (x) => x | true |
| (root https://www.npmjs.com/package/m1) | src/m1/index.js:1:18:1:25 | (x) => x | true |

View File

@@ -1,3 +1,9 @@
| (instance (member NP (root https://www.npmjs.com/package/typeTracking))) | src/typeTracking/index.js:1:1:1:0 | this | true |
| (instance (member NP (root https://www.npmjs.com/package/typeTracking))) | src/typeTracking/index.js:12:1:12:12 | NP.prototype | true |
| (instance (member NP (root https://www.npmjs.com/package/typeTracking))) | src/typeTracking/index.js:12:25:12:24 | this | true |
| (instance (member NP (root https://www.npmjs.com/package/typeTracking))) | src/typeTracking/index.js:16:1:16:12 | NP.prototype | true |
| (instance (member NP (root https://www.npmjs.com/package/typeTracking))) | src/typeTracking/index.js:16:24:16:23 | this | true |
| (instance (member NP (root https://www.npmjs.com/package/typeTracking))) | src/typeTracking/nonlocalDataflowRead.js:4:10:4:16 | new n() | true |
| (instance (member Promise (root https://www.npmjs.com/package/bluebird))) | src/bluebird/index.js:1:1:1:0 | this | true |
| (instance (member Promise (root https://www.npmjs.com/package/bluebird))) | src/bluebird/index.js:5:1:5:17 | Promise.prototype | true |
| (instance (member Promise (root https://www.npmjs.com/package/bluebird))) | src/bluebird/index.js:5:26:5:25 | this | true |
@@ -9,6 +15,8 @@
| (instance (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:11 | new A("me") | false |
| (instance (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:4:1:4:11 | new A("me") | false |
| (instance (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:5:1:5:11 | new A("me") | false |
| (member argFunc (return (member createNP (instance (member NP (root https://www.npmjs.com/package/typeTracking)))))) | src/typeTracking/nonlocalDataflowRead.js:11:3:11:27 | getPort ... argFunc | true |
| (member createNP (instance (member NP (root https://www.npmjs.com/package/typeTracking)))) | src/typeTracking/nonlocalDataflowRead.js:7:9:7:19 | np.createNP | true |
| (member default (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:1:8:1:8 | A | false |
| (member foo (root https://www.npmjs.com/package/m2)) | src/m3/tst2.js:1:10:1:12 | foo | false |
| (member m (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | false |
@@ -26,7 +34,9 @@
| (member s (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:3:1:3:3 | A.s | false |
| (member x (parameter 0 (member foo (root https://www.npmjs.com/package/m2)))) | src/m2/main.js:2:15:2:17 | p.x | true |
| (member y (member x (parameter 0 (member foo (root https://www.npmjs.com/package/m2))))) | src/m2/main.js:2:15:2:19 | p.x.y | true |
| (parameter 0 (member NP (root https://www.npmjs.com/package/typeTracking))) | src/typeTracking/index.js:1:13:1:16 | exec | true |
| (parameter 0 (member Promise (root https://www.npmjs.com/package/bluebird))) | src/bluebird/index.js:1:18:1:21 | exec | true |
| (parameter 0 (member argFunc (instance (member NP (root https://www.npmjs.com/package/typeTracking))))) | src/typeTracking/index.js:16:33:16:44 | someCallback | true |
| (parameter 0 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:1:14:1:15 | cb | true |
| (parameter 0 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic))))))))) | src/cyclic/index.js:1:14:1:15 | cb | true |
| (parameter 0 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (return (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:1:14:1:15 | cb | true |
@@ -730,6 +740,8 @@
| (parameter 0 (return (return (return (return (return (return (return (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:1:14:1:15 | cb | true |
| (parameter 0 (root https://www.npmjs.com/package/m1)) | src/m1/index.js:1:19:1:19 | x | true |
| (parameter 1 (member then (instance (member Promise (root https://www.npmjs.com/package/bluebird))))) | src/bluebird/index.js:5:46:5:53 | rejected | true |
| (return (member argFunc (return (member createNP (instance (member NP (root https://www.npmjs.com/package/typeTracking))))))) | src/typeTracking/nonlocalDataflowRead.js:11:3:11:29 | getPort ... gFunc() | true |
| (return (member createNP (instance (member NP (root https://www.npmjs.com/package/typeTracking))))) | src/typeTracking/nonlocalDataflowRead.js:7:9:7:21 | np.createNP() | true |
| (return (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:1:4:11 | new A("me") | false |
| (return (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:11 | new A("me") | false |
| (return (member foo (root https://www.npmjs.com/package/m2))) | src/m3/tst2.js:5:1:5:13 | foo({ x: o }) | false |
@@ -745,6 +757,7 @@
| (return (member s (return (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | false |
| (return (member s (return (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | false |
| (return (member s (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:3:1:3:12 | A.s("there") | false |
| (return (parameter 0 (member argFunc (instance (member NP (root https://www.npmjs.com/package/typeTracking)))))) | src/typeTracking/index.js:17:2:17:15 | someCallback() | true |
| (return (parameter 0 (member f00 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:2:3:2:9 | cb(foo) | true |
| (return (parameter 0 (member f00 (member f00 (member f00 (member f00 (member f00 (member foo (root https://www.npmjs.com/package/cyclic))))))))) | src/cyclic/index.js:2:3:2:9 | cb(foo) | true |
| (return (parameter 0 (member f00 (member f00 (member f00 (member f00 (member f00 (return (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:2:3:2:9 | cb(foo) | true |
@@ -1040,4 +1053,4 @@
| (root https://www.npmjs.com/package/m1) | src/m3/index.js:1:10:1:22 | require("m1") | false |
| (root https://www.npmjs.com/package/m2) | src/m3/tst2.js:1:1:1:25 | import ... m "m2"; | false |
| (root https://www.npmjs.com/package/m2) | src/m3/tst3.js:1:1:1:19 | import A from "m2"; | false |
| (root https://www.npmjs.com/package/m2) | src/m3/tst3.js:1:8:1:8 | A | false |
| (root https://www.npmjs.com/package/m2) | src/m3/tst3.js:1:8:1:8 | A | false |

View File

@@ -0,0 +1,20 @@
function NP(exec) {
this.exec = exec
}
function tempObj() {
}
tempObj.prototype.f = function(someCallback) {
someCallback();
};
NP.prototype.createNP = function() {
return new tempObj();
};
NP.prototype.argFunc = function(someCallback) {
someCallback();
}
exports.NP = NP;

View File

@@ -0,0 +1,12 @@
var n = require('./index').NP;
var np = new n();
function getPortalReturn() {
return np.createNP();
}
function main() {
getPortalReturn().argFunc(); // nonlocal property access
}

View File

@@ -0,0 +1,3 @@
{
"name": "typeTracking"
}