JS: Also propagate out of returns

This commit is contained in:
Asger Feldthaus 2020-02-07 11:04:29 +00:00
Родитель 8c36b999cc
Коммит e8e649102f
5 изменённых файлов: 72 добавлений и 5 удалений

Просмотреть файл

@ -751,7 +751,7 @@ private predicate flowThroughCall(
) {
exists(Function f, DataFlow::ValueNode ret |
ret.asExpr() = f.getAReturnedExpr() and
calls(output, f) and // Do not consider partial calls
(calls(output, f) or callsBound(output, f, _)) and // Do not consider partial calls
reachableFromInput(f, output, input, ret, cfg, summary) and
not isBarrierEdge(cfg, ret, output) and
not isLabeledBarrierEdge(cfg, ret, output, summary.getEndLabel()) and
@ -761,7 +761,7 @@ private predicate flowThroughCall(
exists(Function f, DataFlow::Node invk, DataFlow::Node ret |
DataFlow::exceptionalFunctionReturnNode(ret, f) and
DataFlow::exceptionalInvocationReturnNode(output, invk.asExpr()) and
calls(invk, f) and
(calls(invk, f) or callsBound(invk, f, _)) and
reachableFromInput(f, invk, input, ret, cfg, summary) and
not isBarrierEdge(cfg, ret, output) and
not isLabeledBarrierEdge(cfg, ret, output, summary.getEndLabel()) and

Просмотреть файл

@ -179,7 +179,7 @@ private module CachedSteps {
*/
cached
predicate returnStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Function f | calls(succ, f) |
exists(Function f | calls(succ, f) or callsBound(succ, f, _) |
returnExpr(f, pred, _)
or
succ instanceof DataFlow::NewNode and
@ -188,8 +188,11 @@ private module CachedSteps {
or
exists(InvokeExpr invoke, Function fun |
DataFlow::exceptionalFunctionReturnNode(pred, fun) and
DataFlow::exceptionalInvocationReturnNode(succ, invoke) and
DataFlow::exceptionalInvocationReturnNode(succ, invoke)
|
calls(invoke.flow(), fun)
or
callsBound(invoke.flow(), fun, _)
)
}
@ -485,4 +488,3 @@ module PathSummary {
*/
PathSummary return() { exists(FlowLabel lbl | result = MkPathSummary(true, false, lbl, lbl)) }
}

Просмотреть файл

@ -15,6 +15,11 @@ typeInferenceMismatch
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:22:10:22:10 | x |
| bound-function.js:12:12:12:19 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:14:6:14:13 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:45:10:45:17 | source() | bound-function.js:45:6:45:18 | id3(source()) |
| bound-function.js:49:12:49:19 | source() | bound-function.js:54:6:54:14 | source0() |
| bound-function.js:49:12:49:19 | source() | bound-function.js:55:6:55:14 | source1() |
| callbacks.js:4:6:4:13 | source() | callbacks.js:34:27:34:27 | x |
| callbacks.js:4:6:4:13 | source() | callbacks.js:35:27:35:27 | x |
| callbacks.js:5:6:5:13 | source() | callbacks.js:34:27:34:27 | x |

Просмотреть файл

@ -6,6 +6,11 @@
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:22:10:22:10 | x |
| bound-function.js:12:12:12:19 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:14:6:14:13 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:45:10:45:17 | source() | bound-function.js:45:6:45:18 | id3(source()) |
| bound-function.js:49:12:49:19 | source() | bound-function.js:54:6:54:14 | source0() |
| bound-function.js:49:12:49:19 | source() | bound-function.js:55:6:55:14 | source1() |
| callbacks.js:4:6:4:13 | source() | callbacks.js:34:27:34:27 | x |
| callbacks.js:4:6:4:13 | source() | callbacks.js:35:27:35:27 | x |
| callbacks.js:5:6:5:13 | source() | callbacks.js:34:27:34:27 | x |

Просмотреть файл

@ -0,0 +1,55 @@
import * as dummy from 'dummy';
function foo(x, y) {
sink(y);
}
let foo0 = foo.bind(null);
let foo1 = foo.bind(null, null);
let foo2 = foo.bind(null, null, null);
foo0(source(), null); // OK
foo0(null, source()); // NOT OK
foo1(source()); // NOT OK
foo1(null, source()); // OK
foo2(source()); // OK
foo2(null, source()); // OK
function takesCallback(cb) {
cb(source()); // NOT OK - but not found
}
function callback(x, y) {
sink(y);
}
takesCallback(callback.bind(null, null));
function id(x) {
return x;
}
let sourceGetter = id.bind(null, source());
let constGetter = id.bind(null, 'safe');
sink(sourceGetter()); // NOT OK - but not flagged
sink(constGetter()); // OK
function id2(x, y) {
return y;
}
let id3 = id2.bind(null, null);
sink(id3(source())); // NOT OK
sink(id3('safe')); // OK
function getSource() {
return source();
}
let source0 = getSource.bind(null);
let source1 = getSource.bind(null, null);
sink(source0()); // NOT OK
sink(source1()); // NOT OK