From 707f75f7ba5b77eecd1d56931c408292fe4268da Mon Sep 17 00:00:00 2001 From: Joshua Hale Date: Wed, 30 Jan 2019 11:36:48 +0000 Subject: [PATCH 001/134] doc: remove - from command arguments --- java/ql/src/Security/CWE/CWE-078/ExecUnescaped.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.java b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.java index 1529c1fd203..ab831d15873 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.java +++ b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.java @@ -4,7 +4,7 @@ class Test { { String latlonCoords = args[1]; Runtime rt = Runtime.getRuntime(); - Process exec = rt.exec("cmd.exe /C latlon2utm.exe -" + latlonCoords); + Process exec = rt.exec("cmd.exe /C latlon2utm.exe " + latlonCoords); } // GOOD: use an array of arguments instead of executing a string From 1f7dda7fbc07864bb5a631becc050891ee616714 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 6 Feb 2020 12:53:12 +0100 Subject: [PATCH 002/134] add dataflow barrier for if(xrandr) --- .../CWE-400/PrototypePollutionUtility.ql | 11 --------- .../javascript/dataflow/Configuration.qll | 15 ++++++++++++ .../CWE-022/TaintedPath/TaintedPath.js | 24 +++++++++++++++++++ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index 376e2e16f56..f27036c9369 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -348,17 +348,6 @@ class PropNameTracking extends DataFlow::Configuration { ) } - override predicate isBarrier(DataFlow::Node node) { - super.isBarrier(node) - or - exists(ConditionGuardNode guard, SsaRefinementNode refinement | - node = DataFlow::ssaDefinitionNode(refinement) and - refinement.getGuard() = guard and - guard.getTest() instanceof VarAccess and - guard.getOutcome() = false - ) - } - override predicate isBarrierGuard(DataFlow::BarrierGuardNode node) { node instanceof BlacklistEqualityGuard or node instanceof WhitelistEqualityGuard or diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index f281a8aa23e..b35285d936d 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1480,3 +1480,18 @@ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, Dat override predicate appliesTo(Configuration cfg) { f.appliesTo(cfg) } } + +/** A check of the `if(x)`, which sanitizes `x` in its "else" branch. */ +private class VarAccessBarrierGuard extends AdditionalBarrierGuardNode, DataFlow::Node { + VarAccess var; + + VarAccessBarrierGuard() { + var = this.getEnclosingExpr() + } + + override predicate blocks(boolean outcome, Expr e) { + var = e and outcome = false + } + + override predicate appliesTo(Configuration cfg) { any() } +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js index ece2d44a113..bba27255690 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js @@ -114,3 +114,27 @@ var server = http.createServer(function(req, res) { ); }); + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + if (path) { // sanitization + path = path.replace(/[\]\[*,;'"`<>\\?\/]/g, ''); // remove all invalid characters from states plus slashes + path = path.replace(/\.\./g, ''); // remove all ".." + } + + res.write(fs.readFileSync(path)); // OK. Is sanitized above. +}); + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + if (!path) { + + } else { // sanitization + path = path.replace(/[\]\[*,;'"`<>\\?\/]/g, ''); // remove all invalid characters from states plus slashes + path = path.replace(/\.\./g, ''); // remove all ".." + } + + res.write(fs.readFileSync(path)); // OK. Is sanitized above. +}); From ade93e66e1b5a650cdb49527c33a29dbcdfa2a60 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 6 Feb 2020 15:44:22 +0100 Subject: [PATCH 003/134] move the if(!x) from DataFLow to TaintTracking --- .../Security/CWE-400/PrototypePollutionUtility.ql | 3 ++- .../semmle/javascript/dataflow/Configuration.qll | 9 +++++---- .../semmle/javascript/dataflow/TaintTracking.qll | 15 +++++++++++++++ .../javascript/security/dataflow/TaintedPath.qll | 3 ++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index f27036c9369..6923b78d9d8 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -356,7 +356,8 @@ class PropNameTracking extends DataFlow::Configuration { node instanceof InstanceOfGuard or node instanceof TypeofGuard or node instanceof BlacklistInclusionGuard or - node instanceof WhitelistInclusionGuard + node instanceof WhitelistInclusionGuard or + node instanceof DataFlow::VarAccessBarrierGuard } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index b35285d936d..6f9b78780f7 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1481,8 +1481,11 @@ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, Dat override predicate appliesTo(Configuration cfg) { f.appliesTo(cfg) } } -/** A check of the `if(x)`, which sanitizes `x` in its "else" branch. */ -private class VarAccessBarrierGuard extends AdditionalBarrierGuardNode, DataFlow::Node { +/** + * A check of the `if(x)`, which sanitizes `x` in its "else" branch. + * Can be added to a `isBarrierGuard` in a configuration to add the sanitization. + */ +class VarAccessBarrierGuard extends BarrierGuardNode, DataFlow::Node { VarAccess var; VarAccessBarrierGuard() { @@ -1492,6 +1495,4 @@ private class VarAccessBarrierGuard extends AdditionalBarrierGuardNode, DataFlow override predicate blocks(boolean outcome, Expr e) { var = e and outcome = false } - - override predicate appliesTo(Configuration cfg) { any() } } \ No newline at end of file diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index be1df8bc7c2..fa573cf908a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -914,4 +914,19 @@ module TaintTracking { DataFlow::localFlowStep(pred, succ) or any(AdditionalTaintStep s).step(pred, succ) } + + /** A check of the form `if(x)`, which sanitizes `x` in its "else" branch. */ + private class VarAccessBarrierGuard extends AdditionalSanitizerGuardNode, DataFlow::Node { + DataFlow::VarAccessBarrierGuard guard; + + VarAccessBarrierGuard() { + this = guard + } + + override predicate sanitizes(boolean outcome, Expr e) { + guard.blocks(outcome, e) + } + + override predicate appliesTo(Configuration cfg) { any() } + } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index b46f7d508f7..5e888b6e768 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -35,7 +35,8 @@ module TaintedPath { guard instanceof StartsWithDotDotSanitizer or guard instanceof StartsWithDirSanitizer or guard instanceof IsAbsoluteSanitizer or - guard instanceof ContainsDotDotSanitizer + guard instanceof ContainsDotDotSanitizer or + guard instanceof DataFlow::VarAccessBarrierGuard } override predicate isAdditionalFlowStep( From 28657230590823a8143aa8566dea202c70950a1b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 6 Feb 2020 15:44:33 +0100 Subject: [PATCH 004/134] add test for new barrier --- .../TaintTracking/BasicTaintTracking.expected | 2 ++ .../library-tests/TaintTracking/sanitizer-guards.js | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 22c9a6c4576..097f3559794 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -79,6 +79,8 @@ typeInferenceMismatch | sanitizer-guards.js:43:11:43:18 | source() | sanitizer-guards.js:45:8:45:8 | x | | sanitizer-guards.js:43:11:43:18 | source() | sanitizer-guards.js:48:10:48:10 | x | | sanitizer-guards.js:68:11:68:18 | source() | sanitizer-guards.js:75:8:75:8 | x | +| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x | +| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x | | spread.js:2:15:2:22 | source() | spread.js:4:8:4:19 | { ...taint } | | spread.js:2:15:2:22 | source() | spread.js:5:8:5:43 | { f: 'h ... orld' } | | spread.js:2:15:2:22 | source() | spread.js:7:8:7:19 | [ ...taint ] | diff --git a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js index 8549776d5dc..caae61eba6f 100644 --- a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js +++ b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js @@ -74,3 +74,15 @@ function phi2() { } sink(x); // NOT OK } + +function falsy() { + let x = source(); + + sink(x); // NOT OK + + if (x) { + sink(x); // NOT OK + } else { + sink(x); // OK + } +} From 75f23a189deb6803849a58a31674cddc83a3ddd0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 6 Feb 2020 15:53:03 +0100 Subject: [PATCH 005/134] update docstring Co-Authored-By: Asger F --- .../ql/src/semmle/javascript/dataflow/Configuration.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 6f9b78780f7..873a1dbed6a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1482,7 +1482,7 @@ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, Dat } /** - * A check of the `if(x)`, which sanitizes `x` in its "else" branch. + * A check of the form `if(x)`, which sanitizes `x` in its "else" branch. * Can be added to a `isBarrierGuard` in a configuration to add the sanitization. */ class VarAccessBarrierGuard extends BarrierGuardNode, DataFlow::Node { @@ -1495,4 +1495,4 @@ class VarAccessBarrierGuard extends BarrierGuardNode, DataFlow::Node { override predicate blocks(boolean outcome, Expr e) { var = e and outcome = false } -} \ No newline at end of file +} From 1ece6b9afecf351ae9f911ac49c535032116415d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 7 Feb 2020 12:55:42 +0100 Subject: [PATCH 006/134] update expected output of tests --- .../TaintBarriers/SanitizingGuard.expected | 351 ++++++++++++++++++ .../TaintTracking/DataFlowTracking.expected | 3 + .../TaintTracking/sanitizer-guards.js | 4 +- 3 files changed, 356 insertions(+), 2 deletions(-) diff --git a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected index cf568e8c593..d09005ef78b 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected @@ -1,68 +1,419 @@ +| tst.js:2:13:2:18 | SOURCE | ExampleConfiguration | false | tst.js:2:13:2:18 | SOURCE | +| tst.js:3:5:3:8 | SINK | ExampleConfiguration | false | tst.js:3:5:3:8 | SINK | +| tst.js:3:10:3:10 | v | ExampleConfiguration | false | tst.js:3:10:3:10 | v | | tst.js:5:9:5:21 | /^x$/.test(v) | ExampleConfiguration | true | tst.js:5:20:5:20 | v | +| tst.js:5:20:5:20 | v | ExampleConfiguration | false | tst.js:5:20:5:20 | v | +| tst.js:6:9:6:12 | SINK | ExampleConfiguration | false | tst.js:6:9:6:12 | SINK | +| tst.js:6:14:6:14 | v | ExampleConfiguration | false | tst.js:6:14:6:14 | v | +| tst.js:8:9:8:12 | SINK | ExampleConfiguration | false | tst.js:8:9:8:12 | SINK | +| tst.js:8:14:8:14 | v | ExampleConfiguration | false | tst.js:8:14:8:14 | v | +| tst.js:11:9:11:9 | v | ExampleConfiguration | false | tst.js:11:9:11:9 | v | | tst.js:11:9:11:25 | v.match(/[^a-z]/) | ExampleConfiguration | false | tst.js:11:9:11:9 | v | +| tst.js:12:9:12:12 | SINK | ExampleConfiguration | false | tst.js:12:9:12:12 | SINK | +| tst.js:12:14:12:14 | v | ExampleConfiguration | false | tst.js:12:14:12:14 | v | +| tst.js:14:9:14:12 | SINK | ExampleConfiguration | false | tst.js:14:9:14:12 | SINK | +| tst.js:14:14:14:14 | v | ExampleConfiguration | false | tst.js:14:14:14:14 | v | +| tst.js:20:13:20:18 | SOURCE | ExampleConfiguration | false | tst.js:20:13:20:18 | SOURCE | +| tst.js:21:5:21:8 | SINK | ExampleConfiguration | false | tst.js:21:5:21:8 | SINK | +| tst.js:21:10:21:10 | v | ExampleConfiguration | false | tst.js:21:10:21:10 | v | +| tst.js:23:9:23:9 | o | ExampleConfiguration | false | tst.js:23:9:23:9 | o | | tst.js:23:9:23:27 | o.hasOwnProperty(v) | ExampleConfiguration | true | tst.js:23:26:23:26 | v | +| tst.js:23:26:23:26 | v | ExampleConfiguration | false | tst.js:23:26:23:26 | v | +| tst.js:24:9:24:12 | SINK | ExampleConfiguration | false | tst.js:24:9:24:12 | SINK | +| tst.js:24:14:24:14 | v | ExampleConfiguration | false | tst.js:24:14:24:14 | v | +| tst.js:26:9:26:12 | SINK | ExampleConfiguration | false | tst.js:26:9:26:12 | SINK | +| tst.js:26:14:26:14 | v | ExampleConfiguration | false | tst.js:26:14:26:14 | v | +| tst.js:32:13:32:18 | SOURCE | ExampleConfiguration | false | tst.js:32:13:32:18 | SOURCE | +| tst.js:33:5:33:8 | SINK | ExampleConfiguration | false | tst.js:33:5:33:8 | SINK | +| tst.js:33:10:33:10 | v | ExampleConfiguration | false | tst.js:33:10:33:10 | v | +| tst.js:35:9:35:9 | v | ExampleConfiguration | false | tst.js:35:9:35:9 | v | | tst.js:35:9:35:14 | v in o | ExampleConfiguration | true | tst.js:35:9:35:9 | v | +| tst.js:35:14:35:14 | o | ExampleConfiguration | false | tst.js:35:14:35:14 | o | +| tst.js:36:9:36:12 | SINK | ExampleConfiguration | false | tst.js:36:9:36:12 | SINK | +| tst.js:36:14:36:14 | v | ExampleConfiguration | false | tst.js:36:14:36:14 | v | +| tst.js:38:9:38:12 | SINK | ExampleConfiguration | false | tst.js:38:9:38:12 | SINK | +| tst.js:38:14:38:14 | v | ExampleConfiguration | false | tst.js:38:14:38:14 | v | +| tst.js:44:13:44:18 | SOURCE | ExampleConfiguration | false | tst.js:44:13:44:18 | SOURCE | +| tst.js:45:5:45:8 | SINK | ExampleConfiguration | false | tst.js:45:5:45:8 | SINK | +| tst.js:45:10:45:10 | v | ExampleConfiguration | false | tst.js:45:10:45:10 | v | +| tst.js:47:9:47:9 | o | ExampleConfiguration | false | tst.js:47:9:47:9 | o | | tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | false | tst.js:47:11:47:11 | v | | tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:9:47:12 | o[v] | +| tst.js:47:11:47:11 | v | ExampleConfiguration | false | tst.js:47:11:47:11 | v | +| tst.js:47:17:47:25 | undefined | ExampleConfiguration | false | tst.js:47:17:47:25 | undefined | +| tst.js:48:9:48:12 | SINK | ExampleConfiguration | false | tst.js:48:9:48:12 | SINK | +| tst.js:48:14:48:14 | v | ExampleConfiguration | false | tst.js:48:14:48:14 | v | +| tst.js:50:9:50:12 | SINK | ExampleConfiguration | false | tst.js:50:9:50:12 | SINK | +| tst.js:50:14:50:14 | v | ExampleConfiguration | false | tst.js:50:14:50:14 | v | +| tst.js:53:9:53:17 | undefined | ExampleConfiguration | false | tst.js:53:9:53:17 | undefined | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | false | tst.js:53:25:53:25 | v | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:23:53:26 | o[v] | +| tst.js:53:23:53:23 | o | ExampleConfiguration | false | tst.js:53:23:53:23 | o | +| tst.js:53:25:53:25 | v | ExampleConfiguration | false | tst.js:53:25:53:25 | v | +| tst.js:54:9:54:12 | SINK | ExampleConfiguration | false | tst.js:54:9:54:12 | SINK | +| tst.js:54:14:54:14 | v | ExampleConfiguration | false | tst.js:54:14:54:14 | v | +| tst.js:56:9:56:12 | SINK | ExampleConfiguration | false | tst.js:56:9:56:12 | SINK | +| tst.js:56:14:56:14 | v | ExampleConfiguration | false | tst.js:56:14:56:14 | v | +| tst.js:59:9:59:9 | o | ExampleConfiguration | false | tst.js:59:9:59:9 | o | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:9:59:12 | o[v] | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | true | tst.js:59:11:59:11 | v | +| tst.js:59:11:59:11 | v | ExampleConfiguration | false | tst.js:59:11:59:11 | v | +| tst.js:59:18:59:26 | undefined | ExampleConfiguration | false | tst.js:59:18:59:26 | undefined | +| tst.js:60:9:60:12 | SINK | ExampleConfiguration | false | tst.js:60:9:60:12 | SINK | +| tst.js:60:14:60:14 | v | ExampleConfiguration | false | tst.js:60:14:60:14 | v | +| tst.js:62:9:62:12 | SINK | ExampleConfiguration | false | tst.js:62:9:62:12 | SINK | +| tst.js:62:14:62:14 | v | ExampleConfiguration | false | tst.js:62:14:62:14 | v | +| tst.js:68:13:68:18 | SOURCE | ExampleConfiguration | false | tst.js:68:13:68:18 | SOURCE | +| tst.js:69:5:69:8 | SINK | ExampleConfiguration | false | tst.js:69:5:69:8 | SINK | +| tst.js:69:10:69:10 | v | ExampleConfiguration | false | tst.js:69:10:69:10 | v | +| tst.js:71:9:71:9 | o | ExampleConfiguration | false | tst.js:71:9:71:9 | o | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:19:71:19 | v | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:9:71:20 | o.indexOf(v) | +| tst.js:71:19:71:19 | v | ExampleConfiguration | false | tst.js:71:19:71:19 | v | +| tst.js:72:9:72:12 | SINK | ExampleConfiguration | false | tst.js:72:9:72:12 | SINK | +| tst.js:72:14:72:14 | v | ExampleConfiguration | false | tst.js:72:14:72:14 | v | +| tst.js:74:9:74:12 | SINK | ExampleConfiguration | false | tst.js:74:9:74:12 | SINK | +| tst.js:74:14:74:14 | v | ExampleConfiguration | false | tst.js:74:14:74:14 | v | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:26:77:26 | v | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:16:77:27 | o.indexOf(v) | +| tst.js:77:16:77:16 | o | ExampleConfiguration | false | tst.js:77:16:77:16 | o | +| tst.js:77:26:77:26 | v | ExampleConfiguration | false | tst.js:77:26:77:26 | v | +| tst.js:78:9:78:12 | SINK | ExampleConfiguration | false | tst.js:78:9:78:12 | SINK | +| tst.js:78:14:78:14 | v | ExampleConfiguration | false | tst.js:78:14:78:14 | v | +| tst.js:80:9:80:12 | SINK | ExampleConfiguration | false | tst.js:80:9:80:12 | SINK | +| tst.js:80:14:80:14 | v | ExampleConfiguration | false | tst.js:80:14:80:14 | v | +| tst.js:83:9:83:9 | o | ExampleConfiguration | false | tst.js:83:9:83:9 | o | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:9:83:20 | o.indexOf(v) | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:19:83:19 | v | +| tst.js:83:19:83:19 | v | ExampleConfiguration | false | tst.js:83:19:83:19 | v | +| tst.js:84:9:84:12 | SINK | ExampleConfiguration | false | tst.js:84:9:84:12 | SINK | +| tst.js:84:14:84:14 | v | ExampleConfiguration | false | tst.js:84:14:84:14 | v | +| tst.js:86:9:86:12 | SINK | ExampleConfiguration | false | tst.js:86:9:86:12 | SINK | +| tst.js:86:14:86:14 | v | ExampleConfiguration | false | tst.js:86:14:86:14 | v | +| tst.js:92:13:92:18 | SOURCE | ExampleConfiguration | false | tst.js:92:13:92:18 | SOURCE | +| tst.js:93:5:93:8 | SINK | ExampleConfiguration | false | tst.js:93:5:93:8 | SINK | +| tst.js:93:10:93:10 | v | ExampleConfiguration | false | tst.js:93:10:93:10 | v | +| tst.js:95:9:95:9 | o | ExampleConfiguration | false | tst.js:95:9:95:9 | o | | tst.js:95:9:95:21 | o.contains(v) | ExampleConfiguration | true | tst.js:95:20:95:20 | v | +| tst.js:95:20:95:20 | v | ExampleConfiguration | false | tst.js:95:20:95:20 | v | +| tst.js:96:9:96:12 | SINK | ExampleConfiguration | false | tst.js:96:9:96:12 | SINK | +| tst.js:96:14:96:14 | v | ExampleConfiguration | false | tst.js:96:14:96:14 | v | +| tst.js:98:9:98:12 | SINK | ExampleConfiguration | false | tst.js:98:9:98:12 | SINK | +| tst.js:98:14:98:14 | v | ExampleConfiguration | false | tst.js:98:14:98:14 | v | +| tst.js:104:13:104:18 | SOURCE | ExampleConfiguration | false | tst.js:104:13:104:18 | SOURCE | +| tst.js:105:5:105:8 | SINK | ExampleConfiguration | false | tst.js:105:5:105:8 | SINK | +| tst.js:105:10:105:10 | v | ExampleConfiguration | false | tst.js:105:10:105:10 | v | +| tst.js:107:9:107:9 | o | ExampleConfiguration | false | tst.js:107:9:107:9 | o | | tst.js:107:9:107:16 | o.has(v) | ExampleConfiguration | true | tst.js:107:15:107:15 | v | +| tst.js:107:15:107:15 | v | ExampleConfiguration | false | tst.js:107:15:107:15 | v | +| tst.js:108:9:108:12 | SINK | ExampleConfiguration | false | tst.js:108:9:108:12 | SINK | +| tst.js:108:14:108:14 | v | ExampleConfiguration | false | tst.js:108:14:108:14 | v | +| tst.js:110:9:110:12 | SINK | ExampleConfiguration | false | tst.js:110:9:110:12 | SINK | +| tst.js:110:14:110:14 | v | ExampleConfiguration | false | tst.js:110:14:110:14 | v | +| tst.js:116:13:116:18 | SOURCE | ExampleConfiguration | false | tst.js:116:13:116:18 | SOURCE | +| tst.js:117:5:117:8 | SINK | ExampleConfiguration | false | tst.js:117:5:117:8 | SINK | +| tst.js:117:10:117:10 | v | ExampleConfiguration | false | tst.js:117:10:117:10 | v | +| tst.js:119:9:119:9 | o | ExampleConfiguration | false | tst.js:119:9:119:9 | o | | tst.js:119:9:119:21 | o.includes(v) | ExampleConfiguration | true | tst.js:119:20:119:20 | v | +| tst.js:119:20:119:20 | v | ExampleConfiguration | false | tst.js:119:20:119:20 | v | +| tst.js:120:9:120:12 | SINK | ExampleConfiguration | false | tst.js:120:9:120:12 | SINK | +| tst.js:120:14:120:14 | v | ExampleConfiguration | false | tst.js:120:14:120:14 | v | +| tst.js:122:9:122:12 | SINK | ExampleConfiguration | false | tst.js:122:9:122:12 | SINK | +| tst.js:122:14:122:14 | v | ExampleConfiguration | false | tst.js:122:14:122:14 | v | +| tst.js:128:13:128:18 | SOURCE | ExampleConfiguration | false | tst.js:128:13:128:18 | SOURCE | +| tst.js:129:5:129:8 | SINK | ExampleConfiguration | false | tst.js:129:5:129:8 | SINK | +| tst.js:129:10:129:10 | v | ExampleConfiguration | false | tst.js:129:10:129:10 | v | +| tst.js:131:9:131:9 | o | ExampleConfiguration | false | tst.js:131:9:131:9 | o | | tst.js:131:9:131:27 | o.hasOwnProperty(v) | ExampleConfiguration | true | tst.js:131:26:131:26 | v | +| tst.js:131:26:131:26 | v | ExampleConfiguration | false | tst.js:131:26:131:26 | v | +| tst.js:132:9:132:12 | SINK | ExampleConfiguration | false | tst.js:132:9:132:12 | SINK | +| tst.js:132:14:132:14 | v | ExampleConfiguration | false | tst.js:132:14:132:14 | v | +| tst.js:133:16:133:16 | o | ExampleConfiguration | false | tst.js:133:16:133:16 | o | | tst.js:133:16:133:36 | o.hasOw ... ty(v.p) | ExampleConfiguration | true | tst.js:133:33:133:35 | v.p | +| tst.js:133:33:133:33 | v | ExampleConfiguration | false | tst.js:133:33:133:33 | v | +| tst.js:134:9:134:12 | SINK | ExampleConfiguration | false | tst.js:134:9:134:12 | SINK | +| tst.js:134:14:134:14 | v | ExampleConfiguration | false | tst.js:134:14:134:14 | v | +| tst.js:135:16:135:16 | o | ExampleConfiguration | false | tst.js:135:16:135:16 | o | | tst.js:135:16:135:38 | o.hasOw ... (v.p.q) | ExampleConfiguration | true | tst.js:135:33:135:37 | v.p.q | +| tst.js:135:33:135:33 | v | ExampleConfiguration | false | tst.js:135:33:135:33 | v | +| tst.js:136:9:136:12 | SINK | ExampleConfiguration | false | tst.js:136:9:136:12 | SINK | +| tst.js:136:14:136:14 | v | ExampleConfiguration | false | tst.js:136:14:136:14 | v | +| tst.js:137:16:137:16 | o | ExampleConfiguration | false | tst.js:137:16:137:16 | o | | tst.js:137:16:137:36 | o.hasOw ... ty(v.p) | ExampleConfiguration | true | tst.js:137:33:137:35 | v.p | +| tst.js:137:33:137:33 | v | ExampleConfiguration | false | tst.js:137:33:137:33 | v | +| tst.js:138:9:138:12 | SINK | ExampleConfiguration | false | tst.js:138:9:138:12 | SINK | +| tst.js:138:14:138:14 | v | ExampleConfiguration | false | tst.js:138:14:138:14 | v | +| tst.js:139:16:139:16 | o | ExampleConfiguration | false | tst.js:139:16:139:16 | o | | tst.js:139:16:139:41 | o.hasOw ... "p.q"]) | ExampleConfiguration | true | tst.js:139:33:139:40 | v["p.q"] | +| tst.js:139:33:139:33 | v | ExampleConfiguration | false | tst.js:139:33:139:33 | v | +| tst.js:140:9:140:12 | SINK | ExampleConfiguration | false | tst.js:140:9:140:12 | SINK | +| tst.js:140:14:140:14 | v | ExampleConfiguration | false | tst.js:140:14:140:14 | v | +| tst.js:145:13:145:18 | SOURCE | ExampleConfiguration | false | tst.js:145:13:145:18 | SOURCE | +| tst.js:146:5:146:8 | SINK | ExampleConfiguration | false | tst.js:146:5:146:8 | SINK | +| tst.js:146:10:146:10 | v | ExampleConfiguration | false | tst.js:146:10:146:10 | v | +| tst.js:148:9:148:9 | v | ExampleConfiguration | false | tst.js:148:9:148:9 | v | | tst.js:148:9:148:27 | v == "white-listed" | ExampleConfiguration | true | tst.js:148:9:148:9 | v | | tst.js:148:9:148:27 | v == "white-listed" | ExampleConfiguration | true | tst.js:148:14:148:27 | "white-listed" | +| tst.js:149:9:149:12 | SINK | ExampleConfiguration | false | tst.js:149:9:149:12 | SINK | +| tst.js:149:14:149:14 | v | ExampleConfiguration | false | tst.js:149:14:149:14 | v | +| tst.js:151:9:151:12 | SINK | ExampleConfiguration | false | tst.js:151:9:151:12 | SINK | +| tst.js:151:14:151:14 | v | ExampleConfiguration | false | tst.js:151:14:151:14 | v | | tst.js:154:9:154:27 | "white-listed" != v | ExampleConfiguration | false | tst.js:154:9:154:22 | "white-listed" | | tst.js:154:9:154:27 | "white-listed" != v | ExampleConfiguration | false | tst.js:154:27:154:27 | v | +| tst.js:154:27:154:27 | v | ExampleConfiguration | false | tst.js:154:27:154:27 | v | +| tst.js:155:9:155:12 | SINK | ExampleConfiguration | false | tst.js:155:9:155:12 | SINK | +| tst.js:155:14:155:14 | v | ExampleConfiguration | false | tst.js:155:14:155:14 | v | +| tst.js:157:9:157:12 | SINK | ExampleConfiguration | false | tst.js:157:9:157:12 | SINK | +| tst.js:157:14:157:14 | v | ExampleConfiguration | false | tst.js:157:14:157:14 | v | +| tst.js:160:9:160:9 | v | ExampleConfiguration | false | tst.js:160:9:160:9 | v | | tst.js:160:9:160:30 | v === " ... sted-1" | ExampleConfiguration | true | tst.js:160:9:160:9 | v | | tst.js:160:9:160:30 | v === " ... sted-1" | ExampleConfiguration | true | tst.js:160:15:160:30 | "white-listed-1" | +| tst.js:160:35:160:35 | v | ExampleConfiguration | false | tst.js:160:35:160:35 | v | | tst.js:160:35:160:56 | v === " ... sted-2" | ExampleConfiguration | true | tst.js:160:35:160:35 | v | | tst.js:160:35:160:56 | v === " ... sted-2" | ExampleConfiguration | true | tst.js:160:41:160:56 | "white-listed-2" | +| tst.js:161:9:161:12 | SINK | ExampleConfiguration | false | tst.js:161:9:161:12 | SINK | +| tst.js:161:14:161:14 | v | ExampleConfiguration | false | tst.js:161:14:161:14 | v | +| tst.js:163:9:163:12 | SINK | ExampleConfiguration | false | tst.js:163:9:163:12 | SINK | +| tst.js:163:14:163:14 | v | ExampleConfiguration | false | tst.js:163:14:163:14 | v | +| tst.js:166:9:166:9 | v | ExampleConfiguration | false | tst.js:166:9:166:9 | v | | tst.js:166:9:166:16 | v == !!0 | ExampleConfiguration | true | tst.js:166:9:166:9 | v | | tst.js:166:9:166:16 | v == !!0 | ExampleConfiguration | true | tst.js:166:14:166:16 | !!0 | +| tst.js:167:9:167:12 | SINK | ExampleConfiguration | false | tst.js:167:9:167:12 | SINK | +| tst.js:167:14:167:14 | v | ExampleConfiguration | false | tst.js:167:14:167:14 | v | +| tst.js:169:9:169:12 | SINK | ExampleConfiguration | false | tst.js:169:9:169:12 | SINK | +| tst.js:169:14:169:14 | v | ExampleConfiguration | false | tst.js:169:14:169:14 | v | +| tst.js:174:34:174:34 | x | ExampleConfiguration | false | tst.js:174:34:174:34 | x | +| tst.js:175:13:175:18 | SOURCE | ExampleConfiguration | false | tst.js:175:13:175:18 | SOURCE | +| tst.js:176:5:176:5 | v | ExampleConfiguration | false | tst.js:176:5:176:5 | v | +| tst.js:176:9:176:16 | SANITIZE | ExampleConfiguration | false | tst.js:176:9:176:16 | SANITIZE | +| tst.js:176:18:176:18 | v | ExampleConfiguration | false | tst.js:176:18:176:18 | v | +| tst.js:177:5:177:8 | SINK | ExampleConfiguration | false | tst.js:177:5:177:8 | SINK | +| tst.js:177:10:177:10 | v | ExampleConfiguration | false | tst.js:177:10:177:10 | v | +| tst.js:181:13:181:18 | SOURCE | ExampleConfiguration | false | tst.js:181:13:181:18 | SOURCE | +| tst.js:182:5:182:8 | SINK | ExampleConfiguration | false | tst.js:182:5:182:8 | SINK | +| tst.js:182:10:182:10 | v | ExampleConfiguration | false | tst.js:182:10:182:10 | v | | tst.js:184:9:184:21 | ~o.indexOf(v) | ExampleConfiguration | true | tst.js:184:20:184:20 | v | +| tst.js:184:10:184:10 | o | ExampleConfiguration | false | tst.js:184:10:184:10 | o | +| tst.js:184:20:184:20 | v | ExampleConfiguration | false | tst.js:184:20:184:20 | v | +| tst.js:185:9:185:12 | SINK | ExampleConfiguration | false | tst.js:185:9:185:12 | SINK | +| tst.js:185:14:185:14 | v | ExampleConfiguration | false | tst.js:185:14:185:14 | v | +| tst.js:187:9:187:12 | SINK | ExampleConfiguration | false | tst.js:187:9:187:12 | SINK | +| tst.js:187:14:187:14 | v | ExampleConfiguration | false | tst.js:187:14:187:14 | v | | tst.js:190:10:190:22 | ~o.indexOf(v) | ExampleConfiguration | true | tst.js:190:21:190:21 | v | +| tst.js:190:11:190:11 | o | ExampleConfiguration | false | tst.js:190:11:190:11 | o | +| tst.js:190:21:190:21 | v | ExampleConfiguration | false | tst.js:190:21:190:21 | v | +| tst.js:191:9:191:12 | SINK | ExampleConfiguration | false | tst.js:191:9:191:12 | SINK | +| tst.js:191:14:191:14 | v | ExampleConfiguration | false | tst.js:191:14:191:14 | v | +| tst.js:193:9:193:12 | SINK | ExampleConfiguration | false | tst.js:193:9:193:12 | SINK | +| tst.js:193:14:193:14 | v | ExampleConfiguration | false | tst.js:193:14:193:14 | v | +| tst.js:199:13:199:18 | SOURCE | ExampleConfiguration | false | tst.js:199:13:199:18 | SOURCE | +| tst.js:200:5:200:8 | SINK | ExampleConfiguration | false | tst.js:200:5:200:8 | SINK | +| tst.js:200:10:200:10 | v | ExampleConfiguration | false | tst.js:200:10:200:10 | v | +| tst.js:202:9:202:9 | o | ExampleConfiguration | false | tst.js:202:9:202:9 | o | | tst.js:202:9:202:26 | o.indexOf(v) <= -1 | ExampleConfiguration | false | tst.js:202:19:202:19 | v | +| tst.js:202:19:202:19 | v | ExampleConfiguration | false | tst.js:202:19:202:19 | v | +| tst.js:203:9:203:12 | SINK | ExampleConfiguration | false | tst.js:203:9:203:12 | SINK | +| tst.js:203:14:203:14 | v | ExampleConfiguration | false | tst.js:203:14:203:14 | v | +| tst.js:205:9:205:12 | SINK | ExampleConfiguration | false | tst.js:205:9:205:12 | SINK | +| tst.js:205:14:205:14 | v | ExampleConfiguration | false | tst.js:205:14:205:14 | v | +| tst.js:208:9:208:9 | o | ExampleConfiguration | false | tst.js:208:9:208:9 | o | | tst.js:208:9:208:25 | o.indexOf(v) >= 0 | ExampleConfiguration | true | tst.js:208:19:208:19 | v | +| tst.js:208:19:208:19 | v | ExampleConfiguration | false | tst.js:208:19:208:19 | v | +| tst.js:209:9:209:12 | SINK | ExampleConfiguration | false | tst.js:209:9:209:12 | SINK | +| tst.js:209:14:209:14 | v | ExampleConfiguration | false | tst.js:209:14:209:14 | v | +| tst.js:211:9:211:12 | SINK | ExampleConfiguration | false | tst.js:211:9:211:12 | SINK | +| tst.js:211:14:211:14 | v | ExampleConfiguration | false | tst.js:211:14:211:14 | v | +| tst.js:214:9:214:9 | o | ExampleConfiguration | false | tst.js:214:9:214:9 | o | | tst.js:214:9:214:24 | o.indexOf(v) < 0 | ExampleConfiguration | false | tst.js:214:19:214:19 | v | +| tst.js:214:19:214:19 | v | ExampleConfiguration | false | tst.js:214:19:214:19 | v | +| tst.js:215:9:215:12 | SINK | ExampleConfiguration | false | tst.js:215:9:215:12 | SINK | +| tst.js:215:14:215:14 | v | ExampleConfiguration | false | tst.js:215:14:215:14 | v | +| tst.js:217:9:217:12 | SINK | ExampleConfiguration | false | tst.js:217:9:217:12 | SINK | +| tst.js:217:14:217:14 | v | ExampleConfiguration | false | tst.js:217:14:217:14 | v | +| tst.js:220:9:220:9 | o | ExampleConfiguration | false | tst.js:220:9:220:9 | o | | tst.js:220:9:220:25 | o.indexOf(v) > -1 | ExampleConfiguration | true | tst.js:220:19:220:19 | v | +| tst.js:220:19:220:19 | v | ExampleConfiguration | false | tst.js:220:19:220:19 | v | +| tst.js:221:9:221:12 | SINK | ExampleConfiguration | false | tst.js:221:9:221:12 | SINK | +| tst.js:221:14:221:14 | v | ExampleConfiguration | false | tst.js:221:14:221:14 | v | +| tst.js:223:9:223:12 | SINK | ExampleConfiguration | false | tst.js:223:9:223:12 | SINK | +| tst.js:223:14:223:14 | v | ExampleConfiguration | false | tst.js:223:14:223:14 | v | | tst.js:226:9:226:26 | -1 >= o.indexOf(v) | ExampleConfiguration | false | tst.js:226:25:226:25 | v | +| tst.js:226:15:226:15 | o | ExampleConfiguration | false | tst.js:226:15:226:15 | o | +| tst.js:226:25:226:25 | v | ExampleConfiguration | false | tst.js:226:25:226:25 | v | +| tst.js:227:9:227:12 | SINK | ExampleConfiguration | false | tst.js:227:9:227:12 | SINK | +| tst.js:227:14:227:14 | v | ExampleConfiguration | false | tst.js:227:14:227:14 | v | +| tst.js:229:9:229:12 | SINK | ExampleConfiguration | false | tst.js:229:9:229:12 | SINK | +| tst.js:229:14:229:14 | v | ExampleConfiguration | false | tst.js:229:14:229:14 | v | +| tst.js:235:13:235:18 | SOURCE | ExampleConfiguration | false | tst.js:235:13:235:18 | SOURCE | +| tst.js:236:9:236:21 | isWhitelisted | ExampleConfiguration | false | tst.js:236:9:236:21 | isWhitelisted | | tst.js:236:9:236:24 | isWhitelisted(v) | ExampleConfiguration | true | tst.js:236:23:236:23 | v | +| tst.js:236:23:236:23 | v | ExampleConfiguration | false | tst.js:236:23:236:23 | v | +| tst.js:237:9:237:12 | SINK | ExampleConfiguration | false | tst.js:237:9:237:12 | SINK | +| tst.js:237:14:237:14 | v | ExampleConfiguration | false | tst.js:237:14:237:14 | v | +| tst.js:239:9:239:12 | SINK | ExampleConfiguration | false | tst.js:239:9:239:12 | SINK | +| tst.js:239:14:239:14 | v | ExampleConfiguration | false | tst.js:239:14:239:14 | v | +| tst.js:240:9:240:14 | config | ExampleConfiguration | false | tst.js:240:9:240:14 | config | | tst.js:240:9:240:28 | config.allowValue(v) | ExampleConfiguration | true | tst.js:240:27:240:27 | v | +| tst.js:240:27:240:27 | v | ExampleConfiguration | false | tst.js:240:27:240:27 | v | +| tst.js:241:9:241:12 | SINK | ExampleConfiguration | false | tst.js:241:9:241:12 | SINK | +| tst.js:241:14:241:14 | v | ExampleConfiguration | false | tst.js:241:14:241:14 | v | +| tst.js:243:9:243:12 | SINK | ExampleConfiguration | false | tst.js:243:9:243:12 | SINK | +| tst.js:243:14:243:14 | v | ExampleConfiguration | false | tst.js:243:14:243:14 | v | +| tst.js:248:13:248:18 | SOURCE | ExampleConfiguration | false | tst.js:248:13:248:18 | SOURCE | +| tst.js:249:5:249:8 | SINK | ExampleConfiguration | false | tst.js:249:5:249:8 | SINK | +| tst.js:249:10:249:10 | v | ExampleConfiguration | false | tst.js:249:10:249:10 | v | +| tst.js:252:16:252:24 | whitelist | ExampleConfiguration | false | tst.js:252:16:252:24 | whitelist | | tst.js:252:16:252:36 | whiteli ... ains(x) | ExampleConfiguration | true | tst.js:252:35:252:35 | x | +| tst.js:252:35:252:35 | x | ExampleConfiguration | false | tst.js:252:35:252:35 | x | +| tst.js:254:9:254:9 | f | ExampleConfiguration | false | tst.js:254:9:254:9 | f | +| tst.js:254:11:254:11 | v | ExampleConfiguration | false | tst.js:254:11:254:11 | v | +| tst.js:255:9:255:12 | SINK | ExampleConfiguration | false | tst.js:255:9:255:12 | SINK | +| tst.js:255:14:255:14 | v | ExampleConfiguration | false | tst.js:255:14:255:14 | v | +| tst.js:257:9:257:12 | SINK | ExampleConfiguration | false | tst.js:257:9:257:12 | SINK | +| tst.js:257:14:257:14 | v | ExampleConfiguration | false | tst.js:257:14:257:14 | v | +| tst.js:261:25:261:33 | whitelist | ExampleConfiguration | false | tst.js:261:25:261:33 | whitelist | | tst.js:261:25:261:45 | whiteli ... ains(y) | ExampleConfiguration | true | tst.js:261:44:261:44 | y | +| tst.js:261:44:261:44 | y | ExampleConfiguration | false | tst.js:261:44:261:44 | y | +| tst.js:262:16:262:24 | sanitized | ExampleConfiguration | false | tst.js:262:16:262:24 | sanitized | +| tst.js:264:9:264:9 | g | ExampleConfiguration | false | tst.js:264:9:264:9 | g | +| tst.js:264:11:264:11 | v | ExampleConfiguration | false | tst.js:264:11:264:11 | v | +| tst.js:265:9:265:12 | SINK | ExampleConfiguration | false | tst.js:265:9:265:12 | SINK | +| tst.js:265:14:265:14 | v | ExampleConfiguration | false | tst.js:265:14:265:14 | v | +| tst.js:267:9:267:12 | SINK | ExampleConfiguration | false | tst.js:267:9:267:12 | SINK | +| tst.js:267:14:267:14 | v | ExampleConfiguration | false | tst.js:267:14:267:14 | v | +| tst.js:271:25:271:33 | whitelist | ExampleConfiguration | false | tst.js:271:25:271:33 | whitelist | | tst.js:271:25:271:45 | whiteli ... ains(z) | ExampleConfiguration | true | tst.js:271:44:271:44 | z | +| tst.js:271:44:271:44 | z | ExampleConfiguration | false | tst.js:271:44:271:44 | z | +| tst.js:272:16:272:28 | somethingElse | ExampleConfiguration | false | tst.js:272:16:272:28 | somethingElse | +| tst.js:274:9:274:9 | h | ExampleConfiguration | false | tst.js:274:9:274:9 | h | +| tst.js:274:11:274:11 | v | ExampleConfiguration | false | tst.js:274:11:274:11 | v | +| tst.js:275:9:275:12 | SINK | ExampleConfiguration | false | tst.js:275:9:275:12 | SINK | +| tst.js:275:14:275:14 | v | ExampleConfiguration | false | tst.js:275:14:275:14 | v | +| tst.js:277:9:277:12 | SINK | ExampleConfiguration | false | tst.js:277:9:277:12 | SINK | +| tst.js:277:14:277:14 | v | ExampleConfiguration | false | tst.js:277:14:277:14 | v | +| tst.js:281:16:281:17 | x2 | ExampleConfiguration | false | tst.js:281:16:281:17 | x2 | | tst.js:281:16:281:25 | x2 != null | ExampleConfiguration | false | tst.js:281:16:281:17 | x2 | | tst.js:281:16:281:25 | x2 != null | ExampleConfiguration | false | tst.js:281:22:281:25 | null | +| tst.js:281:30:281:38 | whitelist | ExampleConfiguration | false | tst.js:281:30:281:38 | whitelist | | tst.js:281:30:281:51 | whiteli ... ins(x2) | ExampleConfiguration | true | tst.js:281:49:281:50 | x2 | +| tst.js:281:49:281:50 | x2 | ExampleConfiguration | false | tst.js:281:49:281:50 | x2 | +| tst.js:283:9:283:10 | f2 | ExampleConfiguration | false | tst.js:283:9:283:10 | f2 | +| tst.js:283:12:283:12 | v | ExampleConfiguration | false | tst.js:283:12:283:12 | v | +| tst.js:284:9:284:12 | SINK | ExampleConfiguration | false | tst.js:284:9:284:12 | SINK | +| tst.js:284:14:284:14 | v | ExampleConfiguration | false | tst.js:284:14:284:14 | v | +| tst.js:286:9:286:12 | SINK | ExampleConfiguration | false | tst.js:286:9:286:12 | SINK | +| tst.js:286:14:286:14 | v | ExampleConfiguration | false | tst.js:286:14:286:14 | v | +| tst.js:290:16:290:17 | x3 | ExampleConfiguration | false | tst.js:290:16:290:17 | x3 | | tst.js:290:16:290:25 | x3 == null | ExampleConfiguration | true | tst.js:290:16:290:17 | x3 | | tst.js:290:16:290:25 | x3 == null | ExampleConfiguration | true | tst.js:290:22:290:25 | null | +| tst.js:290:30:290:38 | whitelist | ExampleConfiguration | false | tst.js:290:30:290:38 | whitelist | | tst.js:290:30:290:51 | whiteli ... ins(x3) | ExampleConfiguration | true | tst.js:290:49:290:50 | x3 | +| tst.js:290:49:290:50 | x3 | ExampleConfiguration | false | tst.js:290:49:290:50 | x3 | +| tst.js:292:9:292:10 | f3 | ExampleConfiguration | false | tst.js:292:9:292:10 | f3 | +| tst.js:292:12:292:12 | v | ExampleConfiguration | false | tst.js:292:12:292:12 | v | +| tst.js:293:9:293:12 | SINK | ExampleConfiguration | false | tst.js:293:9:293:12 | SINK | +| tst.js:293:14:293:14 | v | ExampleConfiguration | false | tst.js:293:14:293:14 | v | +| tst.js:295:9:295:12 | SINK | ExampleConfiguration | false | tst.js:295:9:295:12 | SINK | +| tst.js:295:14:295:14 | v | ExampleConfiguration | false | tst.js:295:14:295:14 | v | +| tst.js:299:17:299:25 | whitelist | ExampleConfiguration | false | tst.js:299:17:299:25 | whitelist | | tst.js:299:17:299:38 | whiteli ... ins(x4) | ExampleConfiguration | true | tst.js:299:36:299:37 | x4 | +| tst.js:299:36:299:37 | x4 | ExampleConfiguration | false | tst.js:299:36:299:37 | x4 | +| tst.js:301:9:301:10 | f4 | ExampleConfiguration | false | tst.js:301:9:301:10 | f4 | +| tst.js:301:12:301:12 | v | ExampleConfiguration | false | tst.js:301:12:301:12 | v | +| tst.js:302:9:302:12 | SINK | ExampleConfiguration | false | tst.js:302:9:302:12 | SINK | +| tst.js:302:14:302:14 | v | ExampleConfiguration | false | tst.js:302:14:302:14 | v | +| tst.js:304:9:304:12 | SINK | ExampleConfiguration | false | tst.js:304:9:304:12 | SINK | +| tst.js:304:14:304:14 | v | ExampleConfiguration | false | tst.js:304:14:304:14 | v | +| tst.js:308:18:308:26 | whitelist | ExampleConfiguration | false | tst.js:308:18:308:26 | whitelist | | tst.js:308:18:308:39 | whiteli ... ins(x5) | ExampleConfiguration | true | tst.js:308:37:308:38 | x5 | +| tst.js:308:37:308:38 | x5 | ExampleConfiguration | false | tst.js:308:37:308:38 | x5 | +| tst.js:310:9:310:10 | f5 | ExampleConfiguration | false | tst.js:310:9:310:10 | f5 | +| tst.js:310:12:310:12 | v | ExampleConfiguration | false | tst.js:310:12:310:12 | v | +| tst.js:311:9:311:12 | SINK | ExampleConfiguration | false | tst.js:311:9:311:12 | SINK | +| tst.js:311:14:311:14 | v | ExampleConfiguration | false | tst.js:311:14:311:14 | v | +| tst.js:313:9:313:12 | SINK | ExampleConfiguration | false | tst.js:313:9:313:12 | SINK | +| tst.js:313:14:313:14 | v | ExampleConfiguration | false | tst.js:313:14:313:14 | v | +| tst.js:317:26:317:34 | whitelist | ExampleConfiguration | false | tst.js:317:26:317:34 | whitelist | | tst.js:317:26:317:47 | whiteli ... ins(x6) | ExampleConfiguration | true | tst.js:317:45:317:46 | x6 | +| tst.js:317:45:317:46 | x6 | ExampleConfiguration | false | tst.js:317:45:317:46 | x6 | +| tst.js:318:17:318:25 | sanitized | ExampleConfiguration | false | tst.js:318:17:318:25 | sanitized | +| tst.js:320:9:320:10 | f6 | ExampleConfiguration | false | tst.js:320:9:320:10 | f6 | +| tst.js:320:12:320:12 | v | ExampleConfiguration | false | tst.js:320:12:320:12 | v | +| tst.js:321:9:321:12 | SINK | ExampleConfiguration | false | tst.js:321:9:321:12 | SINK | +| tst.js:321:14:321:14 | v | ExampleConfiguration | false | tst.js:321:14:321:14 | v | +| tst.js:323:9:323:12 | SINK | ExampleConfiguration | false | tst.js:323:9:323:12 | SINK | +| tst.js:323:14:323:14 | v | ExampleConfiguration | false | tst.js:323:14:323:14 | v | +| tst.js:327:25:327:26 | x7 | ExampleConfiguration | false | tst.js:327:25:327:26 | x7 | | tst.js:327:25:327:34 | x7 != null | ExampleConfiguration | false | tst.js:327:25:327:26 | x7 | | tst.js:327:25:327:34 | x7 != null | ExampleConfiguration | false | tst.js:327:31:327:34 | null | +| tst.js:327:39:327:47 | whitelist | ExampleConfiguration | false | tst.js:327:39:327:47 | whitelist | | tst.js:327:39:327:60 | whiteli ... ins(x7) | ExampleConfiguration | true | tst.js:327:58:327:59 | x7 | +| tst.js:327:58:327:59 | x7 | ExampleConfiguration | false | tst.js:327:58:327:59 | x7 | +| tst.js:328:16:328:24 | sanitized | ExampleConfiguration | false | tst.js:328:16:328:24 | sanitized | +| tst.js:330:9:330:10 | f7 | ExampleConfiguration | false | tst.js:330:9:330:10 | f7 | +| tst.js:330:12:330:12 | v | ExampleConfiguration | false | tst.js:330:12:330:12 | v | +| tst.js:331:9:331:12 | SINK | ExampleConfiguration | false | tst.js:331:9:331:12 | SINK | +| tst.js:331:14:331:14 | v | ExampleConfiguration | false | tst.js:331:14:331:14 | v | +| tst.js:333:9:333:12 | SINK | ExampleConfiguration | false | tst.js:333:9:333:12 | SINK | +| tst.js:333:14:333:14 | v | ExampleConfiguration | false | tst.js:333:14:333:14 | v | +| tst.js:337:25:337:33 | whitelist | ExampleConfiguration | false | tst.js:337:25:337:33 | whitelist | | tst.js:337:25:337:46 | whiteli ... ins(x8) | ExampleConfiguration | true | tst.js:337:44:337:45 | x8 | +| tst.js:337:44:337:45 | x8 | ExampleConfiguration | false | tst.js:337:44:337:45 | x8 | +| tst.js:338:16:338:17 | x8 | ExampleConfiguration | false | tst.js:338:16:338:17 | x8 | | tst.js:338:16:338:25 | x8 != null | ExampleConfiguration | false | tst.js:338:16:338:17 | x8 | | tst.js:338:16:338:25 | x8 != null | ExampleConfiguration | false | tst.js:338:22:338:25 | null | +| tst.js:338:30:338:38 | sanitized | ExampleConfiguration | false | tst.js:338:30:338:38 | sanitized | +| tst.js:340:9:340:10 | f8 | ExampleConfiguration | false | tst.js:340:9:340:10 | f8 | +| tst.js:340:12:340:12 | v | ExampleConfiguration | false | tst.js:340:12:340:12 | v | +| tst.js:341:9:341:12 | SINK | ExampleConfiguration | false | tst.js:341:9:341:12 | SINK | +| tst.js:341:14:341:14 | v | ExampleConfiguration | false | tst.js:341:14:341:14 | v | +| tst.js:343:9:343:12 | SINK | ExampleConfiguration | false | tst.js:343:9:343:12 | SINK | +| tst.js:343:14:343:14 | v | ExampleConfiguration | false | tst.js:343:14:343:14 | v | +| tst.js:347:16:347:22 | unknown | ExampleConfiguration | false | tst.js:347:16:347:22 | unknown | +| tst.js:347:29:347:37 | whitelist | ExampleConfiguration | false | tst.js:347:29:347:37 | whitelist | | tst.js:347:29:347:50 | whiteli ... ins(x9) | ExampleConfiguration | true | tst.js:347:48:347:49 | x9 | +| tst.js:347:48:347:49 | x9 | ExampleConfiguration | false | tst.js:347:48:347:49 | x9 | +| tst.js:347:55:347:61 | unknown | ExampleConfiguration | false | tst.js:347:55:347:61 | unknown | +| tst.js:349:9:349:10 | f9 | ExampleConfiguration | false | tst.js:349:9:349:10 | f9 | +| tst.js:349:12:349:12 | v | ExampleConfiguration | false | tst.js:349:12:349:12 | v | +| tst.js:350:9:350:12 | SINK | ExampleConfiguration | false | tst.js:350:9:350:12 | SINK | +| tst.js:350:14:350:14 | v | ExampleConfiguration | false | tst.js:350:14:350:14 | v | +| tst.js:352:9:352:12 | SINK | ExampleConfiguration | false | tst.js:352:9:352:12 | SINK | +| tst.js:352:14:352:14 | v | ExampleConfiguration | false | tst.js:352:14:352:14 | v | +| tst.js:356:16:356:18 | x10 | ExampleConfiguration | false | tst.js:356:16:356:18 | x10 | | tst.js:356:16:356:27 | x10 !== null | ExampleConfiguration | false | tst.js:356:16:356:18 | x10 | | tst.js:356:16:356:27 | x10 !== null | ExampleConfiguration | false | tst.js:356:24:356:27 | null | +| tst.js:356:32:356:34 | x10 | ExampleConfiguration | false | tst.js:356:32:356:34 | x10 | | tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:32:356:34 | x10 | | tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:40:356:48 | undefined | +| tst.js:356:40:356:48 | undefined | ExampleConfiguration | false | tst.js:356:40:356:48 | undefined | +| tst.js:358:9:358:11 | f10 | ExampleConfiguration | false | tst.js:358:9:358:11 | f10 | +| tst.js:358:13:358:13 | v | ExampleConfiguration | false | tst.js:358:13:358:13 | v | +| tst.js:359:9:359:12 | SINK | ExampleConfiguration | false | tst.js:359:9:359:12 | SINK | +| tst.js:359:14:359:14 | v | ExampleConfiguration | false | tst.js:359:14:359:14 | v | +| tst.js:361:9:361:12 | SINK | ExampleConfiguration | false | tst.js:361:9:361:12 | SINK | +| tst.js:361:14:361:14 | v | ExampleConfiguration | false | tst.js:361:14:361:14 | v | +| tst.js:367:13:367:18 | SOURCE | ExampleConfiguration | false | tst.js:367:13:367:18 | SOURCE | +| tst.js:368:5:368:8 | SINK | ExampleConfiguration | false | tst.js:368:5:368:8 | SINK | +| tst.js:368:10:368:10 | o | ExampleConfiguration | false | tst.js:368:10:368:10 | o | +| tst.js:370:9:370:9 | o | ExampleConfiguration | false | tst.js:370:9:370:9 | o | | tst.js:370:9:370:29 | o.p == ... listed" | ExampleConfiguration | true | tst.js:370:9:370:11 | o.p | +| tst.js:371:9:371:12 | SINK | ExampleConfiguration | false | tst.js:371:9:371:12 | SINK | +| tst.js:371:14:371:14 | o | ExampleConfiguration | false | tst.js:371:14:371:14 | o | +| tst.js:373:9:373:12 | SINK | ExampleConfiguration | false | tst.js:373:9:373:12 | SINK | +| tst.js:373:14:373:14 | o | ExampleConfiguration | false | tst.js:373:14:373:14 | o | +| tst.js:376:19:376:19 | o | ExampleConfiguration | false | tst.js:376:19:376:19 | o | +| tst.js:377:11:377:11 | o | ExampleConfiguration | false | tst.js:377:11:377:11 | o | | tst.js:377:11:377:32 | o[p] == ... listed" | ExampleConfiguration | true | tst.js:377:11:377:14 | o[p] | +| tst.js:377:13:377:13 | p | ExampleConfiguration | false | tst.js:377:13:377:13 | p | +| tst.js:378:9:378:12 | SINK | ExampleConfiguration | false | tst.js:378:9:378:12 | SINK | +| tst.js:378:14:378:14 | o | ExampleConfiguration | false | tst.js:378:14:378:14 | o | +| tst.js:378:16:378:16 | p | ExampleConfiguration | false | tst.js:378:16:378:16 | p | +| tst.js:379:9:379:9 | p | ExampleConfiguration | false | tst.js:379:9:379:9 | p | +| tst.js:379:13:379:25 | somethingElse | ExampleConfiguration | false | tst.js:379:13:379:25 | somethingElse | +| tst.js:380:9:380:12 | SINK | ExampleConfiguration | false | tst.js:380:9:380:12 | SINK | +| tst.js:380:14:380:14 | o | ExampleConfiguration | false | tst.js:380:14:380:14 | o | +| tst.js:380:16:380:16 | p | ExampleConfiguration | false | tst.js:380:16:380:16 | p | +| tst.js:382:9:382:12 | SINK | ExampleConfiguration | false | tst.js:382:9:382:12 | SINK | +| tst.js:382:14:382:14 | o | ExampleConfiguration | false | tst.js:382:14:382:14 | o | +| tst.js:382:16:382:16 | p | ExampleConfiguration | false | tst.js:382:16:382:16 | p | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 9dd83d53ad1..5a6ef361bb8 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -54,6 +54,9 @@ | sanitizer-guards.js:43:11:43:18 | source() | sanitizer-guards.js:48:10:48:10 | x | | sanitizer-guards.js:43:11:43:18 | source() | sanitizer-guards.js:52:10:52:10 | x | | sanitizer-guards.js:68:11:68:18 | source() | sanitizer-guards.js:75:8:75:8 | x | +| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x | +| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x | +| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:86:7:86:7 | x | | thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field | | thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 | | tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x | diff --git a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js index caae61eba6f..497271d989e 100644 --- a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js +++ b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js @@ -81,8 +81,8 @@ function falsy() { sink(x); // NOT OK if (x) { - sink(x); // NOT OK + sink(x); // OK (for taint-tracking) } else { - sink(x); // OK + sink(x); // NOT OK } } From f942e69482702bbe7458966a814f9fc51bacb05c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 5 Feb 2020 14:18:47 +0000 Subject: [PATCH 007/134] JS: Improve flow through partial invokes --- .../ql/src/semmle/javascript/Closure.qll | 5 ++- .../javascript/dataflow/Configuration.qll | 3 ++ .../src/semmle/javascript/dataflow/Nodes.qll | 41 ++++++++++++++++++- .../dataflow/internal/FlowSteps.qll | 8 +++- .../frameworks/AngularJS/AngularJSCore.qll | 5 ++- 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Closure.qll b/javascript/ql/src/semmle/javascript/Closure.qll index 83b8049d48f..c8adaad42d1 100644 --- a/javascript/ql/src/semmle/javascript/Closure.qll +++ b/javascript/ql/src/semmle/javascript/Closure.qll @@ -267,6 +267,9 @@ module Closure { result = this } - override DataFlow::Node getBoundReceiver() { result = getArgument(1) } + override DataFlow::Node getBoundReceiver(DataFlow::Node callback) { + callback = getArgument(0) and + result = getArgument(1) + } } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index f281a8aa23e..8b25f85de68 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1311,6 +1311,9 @@ class MidPathNode extends PathNode, MkMidNode { or // Skip the exceptional return on functions, as this highlights the entire function. nd = any(DataFlow::FunctionNode f).getExceptionalReturn() + or + // Skip the synthetic 'this' node, as a ThisExpr will be the next node anyway + nd = DataFlow::thisNode(_) } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index 98574813b92..ffb88afadf5 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -1199,6 +1199,13 @@ class PartialInvokeNode extends DataFlow::Node { PartialInvokeNode() { this = range } + /** Gets a node holding a callback invoked by this partial invocation node. */ + DataFlow::Node getACallbackNode() { + isPartialArgument(result, _, _) + or + exists(getBoundReceiver(result)) + } + /** * Holds if `argument` is passed as argument `index` to the function in `callback`. */ @@ -1216,7 +1223,12 @@ class PartialInvokeNode extends DataFlow::Node { /** * Gets the node holding the receiver to be passed to the bound function, if specified. */ - DataFlow::Node getBoundReceiver() { result = range.getBoundReceiver() } + DataFlow::Node getBoundReceiver() { result = range.getBoundReceiver(_) } + + /** + * Gets the node holding the receiver to be passed to the bound function, if specified. + */ + DataFlow::Node getBoundReceiver(DataFlow::Node callback) { result = range.getBoundReceiver(callback) } } module PartialInvokeNode { @@ -1235,9 +1247,17 @@ module PartialInvokeNode { DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) { none() } /** + * DEPRECATED. Use the two-argument version of `getBoundReceiver` instead. + * * Gets the node holding the receiver to be passed to the bound function, if specified. */ + deprecated DataFlow::Node getBoundReceiver() { none() } + + /** + * Gets the node holding the receiver to be passed to `callback`. + */ + DataFlow::Node getBoundReceiver(DataFlow::Node callback) { none() } } /** @@ -1264,7 +1284,8 @@ module PartialInvokeNode { result = this } - override DataFlow::Node getBoundReceiver() { + override DataFlow::Node getBoundReceiver(DataFlow::Node callback) { + callback = getReceiver() and result = getArgument(0) } } @@ -1309,6 +1330,22 @@ module PartialInvokeNode { result = this } } + + /** + * A call to `for-in` or `for-own`, passing the context parameter to the target function. + */ + class ForOwnInPartialCall extends PartialInvokeNode::Range, DataFlow::CallNode { + ForOwnInPartialCall() { + exists(string name | name = "for-in" or name = "for-own" | + this = moduleImport(name).getACall() + ) + } + + override DataFlow::Node getBoundReceiver(DataFlow::Node callback) { + callback = getArgument(1) and + result = getArgument(2) + } + } } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 2ca25905764..bd3e5462116 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -99,7 +99,7 @@ private module CachedSteps { private predicate partiallyCalls( DataFlow::PartialInvokeNode invk, DataFlow::AnalyzedNode callback, Function f ) { - invk.isPartialArgument(callback, _, _) and + callback = invk.getACallbackNode() and exists(AbstractFunction callee | callee = callback.getAValue() | if callback.getAValue().isIndefinite("global") then f = callee.getFunction() and f.getFile() = invk.getFile() @@ -135,6 +135,12 @@ private module CachedSteps { not p.isRestParameter() and parm = DataFlow::parameterNode(p) ) + or + exists(DataFlow::Node callback | + arg = invk.(DataFlow::PartialInvokeNode).getBoundReceiver(callback) and + partiallyCalls(invk, callback, f) and + parm = DataFlow::thisNode(f) + ) } /** diff --git a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll index 45ad2066f2a..6d1aba6bf8e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll @@ -1097,5 +1097,8 @@ private class BindCall extends DataFlow::PartialInvokeNode::Range, DataFlow::Cal result = this } - override DataFlow::Node getBoundReceiver() { result = getArgument(0) } + override DataFlow::Node getBoundReceiver(DataFlow::Node callback) { + callback = getArgument(1) and + result = getArgument(0) + } } From 3b28bdbeeddaedbe0a0ff30a819e224aa212e8c3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 5 Feb 2020 15:28:42 +0000 Subject: [PATCH 008/134] JS: Rewrite AnalyzedThisInArrayIterationFunction --- .../src/semmle/javascript/StandardLibrary.qll | 29 +++++++------------ .../internal/InterProceduralTypeInference.qll | 21 ++++++++++++++ 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 0de4cce8e05..aae98553faf 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -46,33 +46,26 @@ class DirectEval extends CallExpr { } /** - * Flow analysis for `this` expressions inside a function that is called with - * `Array.prototype.map` or a similar Array function that binds `this`. - * - * However, since the function could be invoked in another way, we additionally - * still infer the ordinary abstract value. + * Models `Array.prototype.map` and friends as partial invocations that pass their second + * argument as the receiver to the callback. */ -private class AnalyzedThisInArrayIterationFunction extends AnalyzedNode, DataFlow::ThisNode { - AnalyzedNode thisSource; - - AnalyzedThisInArrayIterationFunction() { - exists(DataFlow::MethodCallNode bindingCall, string name | +private class ArrayIterationCallbackAsPartialInvoke extends DataFlow::PartialInvokeNode::Range, DataFlow::MethodCallNode { + ArrayIterationCallbackAsPartialInvoke() { + getNumArgument() = 2 and + // Filter out library methods named 'forEach' etc + not DataFlow::moduleImport(_).flowsTo(getReceiver()) and + exists(string name | name = getMethodName() | name = "filter" or name = "forEach" or name = "map" or name = "some" or name = "every" - | - name = bindingCall.getMethodName() and - 2 = bindingCall.getNumArgument() and - getBinder() = bindingCall.getCallback(0) and - thisSource = bindingCall.getArgument(1) ) } - override AbstractValue getALocalValue() { - result = thisSource.getALocalValue() or - result = AnalyzedNode.super.getALocalValue() + override DataFlow::Node getBoundReceiver(DataFlow::Node callback) { + callback = getArgument(0) and + result = getArgument(1) } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll index d2243aeff7a..ea46bf36668 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll @@ -274,3 +274,24 @@ private class TypeInferredMethodWithAnalyzedReturnFlow extends CallWithNonLocalA override AnalyzedFunction getACallee() { result = fun } } + +/** + * Propagates receivers into locally defined callbacks of partial invocations. + */ +private class AnalyzedThisInPartialInvokeCallback extends AnalyzedNode, DataFlow::ThisNode { + DataFlow::PartialInvokeNode call; + DataFlow::Node receiver; + + AnalyzedThisInPartialInvokeCallback() { + exists(DataFlow::Node callbackArg | + receiver = call.getBoundReceiver(callbackArg) and + getBinder().flowsTo(callbackArg) + ) + } + + override AbstractValue getALocalValue() { + result = receiver.analyze().getALocalValue() + or + result = AnalyzedNode.super.getALocalValue() + } +} From fea5a4331d9d5dbfbcb7cb9cbf776ed9fdf4d0ee Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 5 Feb 2020 16:14:19 +0000 Subject: [PATCH 009/134] JS: Rewrite React::AnalyzedThisInBoundCallback --- .../semmle/javascript/frameworks/React.qll | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/React.qll b/javascript/ql/src/semmle/javascript/frameworks/React.qll index a8c1793a5cc..3b593e66478 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/React.qll @@ -517,32 +517,24 @@ private class FactoryDefinition extends ReactElementDefinition { } /** - * Flow analysis for `this` expressions inside a function that is called with - * `React.Children.map` or a similar library function that binds `this` of a - * callback. - * - * However, since the function could be invoked in another way, we additionally - * still infer the ordinary abstract value. + * Partial invocation for calls to `React.Children.map` or a similar library function + * that binds `this` of a callback. */ -private class AnalyzedThisInBoundCallback extends AnalyzedNode, DataFlow::ThisNode { - AnalyzedNode thisSource; - - AnalyzedThisInBoundCallback() { - exists(DataFlow::CallNode bindingCall, string binderName | +private class ReactCallbackPartialInvoke extends DataFlow::PartialInvokeNode::Range, DataFlow::CallNode { + ReactCallbackPartialInvoke() { + exists(string name | // React.Children.map or React.Children.forEach - binderName = "map" or - binderName = "forEach" + name = "map" or + name = "forEach" | - bindingCall = react().getAPropertyRead("Children").getAMemberCall(binderName) and - 3 = bindingCall.getNumArgument() and - getBinder() = bindingCall.getCallback(1) and - thisSource = bindingCall.getArgument(2) + this = react().getAPropertyRead("Children").getAMemberCall(name) and + 3 = getNumArgument() ) } - override AbstractValue getALocalValue() { - result = thisSource.getALocalValue() or - result = AnalyzedNode.super.getALocalValue() + override DataFlow::Node getBoundReceiver(DataFlow::Node callback) { + callback = getArgument(1) and + result = getArgument(2) } } From 254af4f3a82958b216057bee681ec1239c0f26fa Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 6 Feb 2020 12:38:54 +0000 Subject: [PATCH 010/134] JS: Rewrite LodashUnderscore::AnalyzedThisInBoundCallback --- .../frameworks/LodashUnderscore.qll | 145 +++++++++--------- 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll b/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll index b900af99d1f..16c8fd851bf 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll @@ -407,103 +407,100 @@ module LodashUnderscore { * However, since the function could be invoked in another way, we additionally * still infer the ordinary abstract value. */ -private class AnalyzedThisInBoundCallback extends AnalyzedNode, DataFlow::ThisNode { - AnalyzedNode thisSource; +private class LodashCallbackAsPartialInvoke extends DataFlow::PartialInvokeNode::Range, + DataFlow::CallNode { + int callbackIndex; + int contextIndex; - AnalyzedThisInBoundCallback() { - exists( - DataFlow::CallNode bindingCall, string binderName, int callbackIndex, int contextIndex, - int argumentCount - | - bindingCall = LodashUnderscore::member(binderName).getACall() and - bindingCall.getNumArgument() = argumentCount and - getBinder() = bindingCall.getCallback(callbackIndex) and - thisSource = bindingCall.getArgument(contextIndex) + LodashCallbackAsPartialInvoke() { + exists(string name, int argumentCount | + this = LodashUnderscore::member(name).getACall() and + getNumArgument() = argumentCount | ( - binderName = "bind" or - binderName = "callback" or - binderName = "iteratee" + name = "bind" or + name = "callback" or + name = "iteratee" ) and callbackIndex = 0 and contextIndex = 1 and argumentCount = 2 or ( - binderName = "all" or - binderName = "any" or - binderName = "collect" or - binderName = "countBy" or - binderName = "detect" or - binderName = "dropRightWhile" or - binderName = "dropWhile" or - binderName = "each" or - binderName = "eachRight" or - binderName = "every" or - binderName = "filter" or - binderName = "find" or - binderName = "findIndex" or - binderName = "findKey" or - binderName = "findLast" or - binderName = "findLastIndex" or - binderName = "findLastKey" or - binderName = "forEach" or - binderName = "forEachRight" or - binderName = "forIn" or - binderName = "forInRight" or - binderName = "groupBy" or - binderName = "indexBy" or - binderName = "map" or - binderName = "mapKeys" or - binderName = "mapValues" or - binderName = "max" or - binderName = "min" or - binderName = "omit" or - binderName = "partition" or - binderName = "pick" or - binderName = "reject" or - binderName = "remove" or - binderName = "select" or - binderName = "some" or - binderName = "sortBy" or - binderName = "sum" or - binderName = "takeRightWhile" or - binderName = "takeWhile" or - binderName = "tap" or - binderName = "thru" or - binderName = "times" or - binderName = "unzipWith" or - binderName = "zipWith" + name = "all" or + name = "any" or + name = "collect" or + name = "countBy" or + name = "detect" or + name = "dropRightWhile" or + name = "dropWhile" or + name = "each" or + name = "eachRight" or + name = "every" or + name = "filter" or + name = "find" or + name = "findIndex" or + name = "findKey" or + name = "findLast" or + name = "findLastIndex" or + name = "findLastKey" or + name = "forEach" or + name = "forEachRight" or + name = "forIn" or + name = "forInRight" or + name = "groupBy" or + name = "indexBy" or + name = "map" or + name = "mapKeys" or + name = "mapValues" or + name = "max" or + name = "min" or + name = "omit" or + name = "partition" or + name = "pick" or + name = "reject" or + name = "remove" or + name = "select" or + name = "some" or + name = "sortBy" or + name = "sum" or + name = "takeRightWhile" or + name = "takeWhile" or + name = "tap" or + name = "thru" or + name = "times" or + name = "unzipWith" or + name = "zipWith" ) and callbackIndex = 1 and contextIndex = 2 and argumentCount = 3 or ( - binderName = "foldl" or - binderName = "foldr" or - binderName = "inject" or - binderName = "reduce" or - binderName = "reduceRight" or - binderName = "transform" + name = "foldl" or + name = "foldr" or + name = "inject" or + name = "reduce" or + name = "reduceRight" or + name = "transform" ) and callbackIndex = 1 and contextIndex = 3 and argumentCount = 4 or ( - binderName = "sortedlastIndex" + name = "sortedlastIndex" or - binderName = "assign" + name = "assign" or - binderName = "eq" + name = "eq" or - binderName = "extend" + name = "extend" or - binderName = "merge" + name = "merge" or - binderName = "sortedIndex" and - binderName = "uniq" + name = "sortedIndex" and + name = "uniq" ) and callbackIndex = 2 and contextIndex = 3 and @@ -511,8 +508,8 @@ private class AnalyzedThisInBoundCallback extends AnalyzedNode, DataFlow::ThisNo ) } - override AbstractValue getALocalValue() { - result = thisSource.getALocalValue() or - result = AnalyzedNode.super.getALocalValue() + override DataFlow::Node getBoundReceiver(DataFlow::Node callback) { + callback = getArgument(callbackIndex) and + result = getArgument(contextIndex) } } From ce28d0fde7fa82696f600d9954116355d8dc2ef4 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Mon, 10 Feb 2020 17:48:44 +0000 Subject: [PATCH 011/134] Remove link to blog --- docs/language/global-sphinx-files/_templates/layout.html | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/language/global-sphinx-files/_templates/layout.html b/docs/language/global-sphinx-files/_templates/layout.html index 7faadbefbe8..f3e19f3ffac 100644 --- a/docs/language/global-sphinx-files/_templates/layout.html +++ b/docs/language/global-sphinx-files/_templates/layout.html @@ -66,7 +66,6 @@ Tools Queries Reference - Blog help.semmle.com
From 2900dced1840b6f0d1ef3b8d5f4d34fbcba9b0eb Mon Sep 17 00:00:00 2001 From: james Date: Fri, 7 Feb 2020 10:26:31 +0000 Subject: [PATCH 012/134] docs: add link to module resolution in ql spec (cherry picked from commit f2320bbe56eaeef1eaf113e5e6d5e568fd663e57) --- docs/language/ql-handbook/modules.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/modules.rst b/docs/language/ql-handbook/modules.rst index 3211fce3897..0d12eb606d9 100644 --- a/docs/language/ql-handbook/modules.rst +++ b/docs/language/ql-handbook/modules.rst @@ -160,7 +160,7 @@ into the :ref:`namespace ` of the current module. Import statements ================= -Import statements are used for importing modules and are of the form:: +Import statements are used for importing modules. They are of the form:: import as import @@ -175,3 +175,6 @@ for example ``import javascript as js``. The ```` itself can be a module name, a selection, or a qualified reference. See :ref:`name-resolution` for more details. + +For information about how import statements are looked up, see `Module resolution `__ +in the QL language specification. \ No newline at end of file From 8e6e6d356dd087fdb6a5671dcafabaf9223691f7 Mon Sep 17 00:00:00 2001 From: james Date: Thu, 2 Jan 2020 15:09:51 +0000 Subject: [PATCH 013/134] docs: move folding predicates topic (cherry picked from commit fe18c1861930ea86c87a3ad75e7ccd04e6bf6979) --- .../learn-ql/advanced/advanced-ql.rst | 1 - .../learn-ql/advanced/folding-predicates.rst | 36 ---------------- .../writing-queries/debugging-queries.rst | 42 +++++++++++++++++++ 3 files changed, 42 insertions(+), 37 deletions(-) delete mode 100644 docs/language/learn-ql/advanced/folding-predicates.rst diff --git a/docs/language/learn-ql/advanced/advanced-ql.rst b/docs/language/learn-ql/advanced/advanced-ql.rst index 67af5a6fb26..b659dc4451d 100644 --- a/docs/language/learn-ql/advanced/advanced-ql.rst +++ b/docs/language/learn-ql/advanced/advanced-ql.rst @@ -13,6 +13,5 @@ Topics on advanced uses of QL. These topics assume that you are familiar with QL - :doc:`Semantics of abstract classes ` - :doc:`Choosing appropriate ways to constrain types ` - :doc:`Determining the most specific types of a variable ` -- :doc:`Folding predicates ` - :doc:`Understanding the difference between != and not(=) ` - :doc:`Monotonic aggregates in QL ` diff --git a/docs/language/learn-ql/advanced/folding-predicates.rst b/docs/language/learn-ql/advanced/folding-predicates.rst deleted file mode 100644 index 0a9d9bb4041..00000000000 --- a/docs/language/learn-ql/advanced/folding-predicates.rst +++ /dev/null @@ -1,36 +0,0 @@ -Folding predicates -================== - -Sometimes you can assist the query optimizer by "folding" parts of predicates out into their own predicates. - -The general principle is to split off chunks of work that are "linear" - that is, there is not too much branching - and tightly bound, such that the chunks then join with each other on as many variables as possible. - -Example -------- - -.. code-block:: ql - - predicate similar(Element e1, Element e2) { - e1.getName() = e2.getName() and - e1.getFile() = e2.getFile() and - e1.getLocation().getStartLine() = e2.getLocation().getStartLine() - } - -Here we explore some lookups on ``Element``\ s. Going from ``Element -> File`` and ``Element -> Location -> StartLine`` are linear: there is only one ``File`` for each ``Element``, and one ``Location`` for each ``Element``, etc. However, as written it is difficult for the optimizer to pick out the best ordering here. We want to do the quick, linear parts first, and then join on the resultant larger tables, rather than joining first and then doing the linear lookups. We can precipitate this kind of ordering by rewriting the above predicate as follows: - -.. code-block:: ql - - predicate locInfo(Element e, string name, File f, int startLine) { - name = e.getName() and - f = e.getFile() and - startLine = e.getLocation().getStartLine() - } - - predicate sameLoc(Element e1, Element e2) { - exists(string name, File f, int startLine | - locInfo(e1, name, f, startLine) and - locInfo(e2, name, f, startLine) - ) - } - -Now the structure we want is clearer: we've separated out the easy part into its own predicate ``locInfo``, and the main predicate is just a larger join. diff --git a/docs/language/learn-ql/writing-queries/debugging-queries.rst b/docs/language/learn-ql/writing-queries/debugging-queries.rst index 9609fa0ac04..2bab05e2529 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -81,6 +81,48 @@ That is, you should define a *base case* that allows the predicate to *bottom ou The query optimizer has special data structures for dealing with `transitive closures `__. If possible, use a transitive closure over a simple recursive predicate, as it is likely to be computed faster. +Folding predicates +~~~~~~~~~~~~~~~~~~ + +Sometimes you can assist the query optimizer by "folding" parts of large predicates out into smaller predicates. + +The general principle is to split off chunks of work that are: + +- **linear**, so that there is not too much branching. +- **tightly bound**, so that the chunks join with each other on as many variables as possible. + + +In the following example, we explore some lookups on two ``Element``\ s: + +.. code-block:: ql + + predicate similar(Element e1, Element e2) { + e1.getName() = e2.getName() and + e1.getFile() = e2.getFile() and + e1.getLocation().getStartLine() = e2.getLocation().getStartLine() + } + +Going from ``Element -> File`` and ``Element -> Location -> StartLine`` is linear--that is, there is only one ``File``, ``Location``, etc. for each ``Element``. + +However, as written it is difficult for the optimizer to pick out the best ordering. Generally, we want to do the quick, linear parts first, and then join on the resultant larger tables. Joining first and then doing the linear lookups later would likely result in poor performance. We can initiate this kind of ordering by splitting the above predicate as follows: + +.. code-block:: ql + + predicate locInfo(Element e, string name, File f, int startLine) { + name = e.getName() and + f = e.getFile() and + startLine = e.getLocation().getStartLine() + } + + predicate sameLoc(Element e1, Element e2) { + exists(string name, File f, int startLine | + locInfo(e1, name, f, startLine) and + locInfo(e2, name, f, startLine) + ) + } + +Now the structure we want is clearer. We've separated out the easy part into its own predicate ``locInfo``, and the main predicate ``sameLoc`` is just a larger join. + Further information ------------------- From bcf08649eea06477927b57309afdb3e1002d434e Mon Sep 17 00:00:00 2001 From: james Date: Thu, 2 Jan 2020 16:47:21 +0000 Subject: [PATCH 014/134] docs: delete equivalence topic (cherry picked from commit e8016a2303b871b59f0e3f942b0f761555c209e9) --- .../learn-ql/advanced/advanced-ql.rst | 1 - .../learn-ql/advanced/equivalence.rst | 44 ------------------- 2 files changed, 45 deletions(-) delete mode 100644 docs/language/learn-ql/advanced/equivalence.rst diff --git a/docs/language/learn-ql/advanced/advanced-ql.rst b/docs/language/learn-ql/advanced/advanced-ql.rst index b659dc4451d..f130c52c39b 100644 --- a/docs/language/learn-ql/advanced/advanced-ql.rst +++ b/docs/language/learn-ql/advanced/advanced-ql.rst @@ -13,5 +13,4 @@ Topics on advanced uses of QL. These topics assume that you are familiar with QL - :doc:`Semantics of abstract classes ` - :doc:`Choosing appropriate ways to constrain types ` - :doc:`Determining the most specific types of a variable ` -- :doc:`Understanding the difference between != and not(=) ` - :doc:`Monotonic aggregates in QL ` diff --git a/docs/language/learn-ql/advanced/equivalence.rst b/docs/language/learn-ql/advanced/equivalence.rst deleted file mode 100644 index bf5efb595d0..00000000000 --- a/docs/language/learn-ql/advanced/equivalence.rst +++ /dev/null @@ -1,44 +0,0 @@ -Understanding the difference between != and not(=) -================================================== - -The two expressions: - -#. ``a() != b()`` -#. ``not(a() = b())`` - -look equivalent - so much so that inexperienced (and even experienced) programmers have been known to rewrite one as the other. However, they are not equivalent due to the quantifiers involved. - -Thinking of ``a()`` and ``b()`` as sets of values, the first expression says that there is a pair of values (one from each side of the inequality) which are different. - -**Using !=** - -:: - - exists x, y | x in a() and y in b() | x != y - -The second expression, however, says that it is *not* the case that there is a pair of values which are the *same* - that is, *all* pairs of values are different: - -**Using not(=)** - -:: - - not exists x, y | x in a() and y in b() | x = y - -This is equivalent to: ``forall x, y | x in a() and y in b() | x != y``. The meaning is very different from the first expression. - -Examples --------- - -``a() = {1, 2}`` and ``b() = {1}``: - -#. ``a() != b()`` is true, because ``2 != 1`` -#. ``a() = b()`` is true, because ``1 = 1`` -#. Therefore\ ``: not(a() = b())`` is false - a different answer from the comparison ``a() != b()`` - -Similarly with ``a() = {}`` and ``b() = {1}``: - -#. ``a() != b()`` is false, because there is no value in ``a()`` that is not equal to ``1`` -#. ``a() = b()`` is also false, because there is no value in ``a()`` that is equal to ``1`` either -#. Therefore: ``not(a() = b())`` is true - again a different answer from the comparison ``a() != b()`` - -In summary, the QL expressions ``a() != b()`` and ``not(a() = b())`` may look similar, but their meaning is quite different. From 646670708c649b2586e6f277beefbd20782d10d5 Mon Sep 17 00:00:00 2001 From: james Date: Fri, 3 Jan 2020 10:54:15 +0000 Subject: [PATCH 015/134] docs: move abstract classes topic to handbook (cherry picked from commit 23d1e06aa49ffeb4a6513f4079c94745b7017cca) --- .../learn-ql/advanced/abstract-classes.rst | 110 ------------------ .../learn-ql/advanced/advanced-ql.rst | 1 - docs/language/ql-handbook/types.rst | 14 ++- 3 files changed, 13 insertions(+), 112 deletions(-) delete mode 100644 docs/language/learn-ql/advanced/abstract-classes.rst diff --git a/docs/language/learn-ql/advanced/abstract-classes.rst b/docs/language/learn-ql/advanced/abstract-classes.rst deleted file mode 100644 index 32441b35996..00000000000 --- a/docs/language/learn-ql/advanced/abstract-classes.rst +++ /dev/null @@ -1,110 +0,0 @@ -Semantics of abstract classes -============================= - -Concrete classes ----------------- - -Concrete classes, as described in the QL language handbook topic on `Classes `__, lend themselves well to top-down modeling. We start from general superclasses representing large sets of values, and carve out individual subclasses representing more restricted sets of values. - -A classic example where this approach is useful is when modeling ASTs (Abstract Syntax Trees): the node types of an AST form a natural inheritance hierarchy, where, for example, there is a class ``Expr`` representing all expression nodes, with many different subclasses for different categories of expressions. There might be a class ``ArithmeticExpr`` representing arithmetic expressions, which in turn could have subclasses ``AddExpr`` and ``SubExpr``. - -Each value in a concrete class satisfies a particular logical property - the *characteristic predicate* (or *character* for short) of that class. This characteristic predicate consists of the conjunction (``and``) of its own body (if any) and the characteristic predicates of its superclasses. - -For example, we could derive a subclass ``MainMethod`` from the standard QL class ``Method`` that contains precisely those Java functions called ``"main"``: - -.. code-block:: ql - - class MainMethod extends Method { - MainMethod() { - hasName("main") - } - } - -.. pull-quote:: - - Note - - - A class ``A`` *extends* a class ``B`` if and only if ``A`` is a subclass of ``B``. - - For a class in QL, the *body* of the characteristic predicate is the logical formula enclosed in curly braces that defines (membership of) the class. In the example, the body of the characteristic predicate of ``MainMethod`` is ``hasName("main")``. - -Letting ``cp(C)`` denote the characteristic predicate of class ``C``, it is clear that: - -.. code-block:: ql - - cp(MainMethod) = cp(Method) and hasName("main") - -That is, entities are *main* methods if and only if they are methods that are also called ``"main"``. - -Abstract classes ----------------- - -In some cases, you might prefer to think of a class as being the union of its subclasses. This can be useful if you want to group multiple existing classes together under a common header and define member predicates on all these classes. - -For example, the security queries in LGTM are interested in identifying all expressions that may be interpreted as SQL queries. We could define an abstract class - -.. code-block:: ql - - abstract class SqlExpr extends Expr { - ... - } - -with various subclasses that identify expressions of interest for different database access libraries. For example, there could be a subclass ``class PostgresSqlExpr extends SqlExpr`` whose character specifies that this must be an expression passed to some Postgres API that performs a database query, and similarly for MySQL and other kinds of database management systems. - -We can simply use ``SqlExpr`` to refer to all of those different expressions. If we want to add support for another database system later on, we can simply add a new subclass to ``SqlExpr``; there is no need to update the queries that rely on it. - -Like a concrete class, an abstract class has one or more superclasses and a characteristic predicate. However, for a value to be in an abstract class, it must not only satisfy the character of the class itself, but it must also satisfy the character of a subclass. In particular, an abstract class without subclasses is empty – since there are no subclasses, there are no values that satisfy the characteristic predicate of one of the subclasses. - -Example -~~~~~~~ - -The following example is taken from the CodeQL library for Java: - -.. code-block:: ql - - abstract class SwitchCase extends Stmt { - } - - /** A constant case of a switch statement. */ - class ConstCase extends SwitchCase, @case { - ConstCase() { exists(Expr e | e.getParent() = this) } - - ... - } - - /** A default case of a switch statement. */ - class DefaultCase extends SwitchCase, @case { - DefaultCase() { not exists(Expr e | e.getParent() = this) } - - ... - } - -It models the two different types of ``case`` in a ``switch`` statement: constant cases of the form ``case e`` that have an expression e, and default cases ``default`` that do not. - -The characteristic predicate of ``SwitchCase`` here is as follows: - -.. code-block:: ql - - cp(SwitchCase) = cp(Stmt) and ( - cp(@case) and exists(Expr e | e.getParent() = this) - or - cp(@case) and not exists(Expr e | e.getParent() = this) - ) - -You must take care when you add a new subclass to an existing abstract class. Adding a subclass is not an isolated change, it also extends the abstract class since that is a union of its subclasses. An extreme example would be extending the ``Call`` class as follows: - -.. code-block:: ql - - class CallEx extends Call { - predicate somethingUseful() - { - ... - } - } - -In this situation, ``cp(CallEx) = cp(Call)``, and then: - -.. code-block:: ql - - cp(Call) = cp(Expr) and (cp(FunctionCall) or ... or cp(DestructorCall) or cp(Call)) = cp(Expr) - -So by adding a bad subclass of ``Call``, we have actually extended ``Call`` to include everything in ``Expr``. This is surprising and completely undesirable. Whilst the specific situation of extending an abstract class without providing any further constraints is now checked for by the QL compiler, extending abstract classes in general is still potentially hazardous. You should think carefully about the effects on the abstract parent class when doing so. \ No newline at end of file diff --git a/docs/language/learn-ql/advanced/advanced-ql.rst b/docs/language/learn-ql/advanced/advanced-ql.rst index f130c52c39b..051d649cf42 100644 --- a/docs/language/learn-ql/advanced/advanced-ql.rst +++ b/docs/language/learn-ql/advanced/advanced-ql.rst @@ -10,7 +10,6 @@ Advanced QL Topics on advanced uses of QL. These topics assume that you are familiar with QL and the basics of query writing. -- :doc:`Semantics of abstract classes ` - :doc:`Choosing appropriate ways to constrain types ` - :doc:`Determining the most specific types of a variable ` - :doc:`Monotonic aggregates in QL ` diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 6aa9043bd62..dfa7a8cd30f 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -208,7 +208,9 @@ by declaring them in the ``from`` part. You can also annotate predicates and fields. See the list of :ref:`annotations ` that are available. -Kinds of classes +.. _concrete-classes: + +Concrete classes ================ The classes in the above examples are all **concrete** classes. They are defined by @@ -218,6 +220,9 @@ values in the intersection of the base types that also satisfy the .. _abstract-classes: +Abstract classes +================ + A class :ref:`annotated ` with ``abstract``, known as an **abstract** class, is also a restriction of the values in a larger type. However, an abstract class is defined as the union of its subclasses. In particular, for a value to be in an abstract class, it must satisfy the @@ -247,6 +252,13 @@ The abstract class ``SqlExpr`` refers to all of those different expressions. If support for another database system later on, you can simply add a new subclass to ``SqlExpr``; there is no need to update the queries that rely on it. +.. pull-quote:: Important + + + You must take care when you add a new subclass to an existing abstract class. Adding a subclass + is not an isolated change, it also extends the abstract class since that is a union of its + subclasses. + .. _overriding-member-predicates: Overriding member predicates From f3d2588dae3a07dea9258501aa70b86bf7564eaf Mon Sep 17 00:00:00 2001 From: james Date: Fri, 3 Jan 2020 15:31:31 +0000 Subject: [PATCH 016/134] docs: address review comments (cherry picked from commit 537739c42d90c7caa6ec000ee31bb2b96b348c8c) --- .../writing-queries/debugging-queries.rst | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/language/learn-ql/writing-queries/debugging-queries.rst b/docs/language/learn-ql/writing-queries/debugging-queries.rst index 2bab05e2529..7fb578e5aa0 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -97,28 +97,28 @@ In the following example, we explore some lookups on two ``Element``\ s: .. code-block:: ql predicate similar(Element e1, Element e2) { - e1.getName() = e2.getName() and - e1.getFile() = e2.getFile() and - e1.getLocation().getStartLine() = e2.getLocation().getStartLine() + e1.getName() = e2.getName() and + e1.getFile() = e2.getFile() and + e1.getLocation().getStartLine() = e2.getLocation().getStartLine() } Going from ``Element -> File`` and ``Element -> Location -> StartLine`` is linear--that is, there is only one ``File``, ``Location``, etc. for each ``Element``. -However, as written it is difficult for the optimizer to pick out the best ordering. Generally, we want to do the quick, linear parts first, and then join on the resultant larger tables. Joining first and then doing the linear lookups later would likely result in poor performance. We can initiate this kind of ordering by splitting the above predicate as follows: +However, as written it is difficult for the optimizer to pick out the best ordering. Joining first and then doing the linear lookups later would likely result in poor performance. Generally, we want to do the quick, linear parts first, and then join on the resultant larger tables. We can initiate this kind of ordering by splitting the above predicate as follows: .. code-block:: ql predicate locInfo(Element e, string name, File f, int startLine) { - name = e.getName() and - f = e.getFile() and - startLine = e.getLocation().getStartLine() + name = e.getName() and + f = e.getFile() and + startLine = e.getLocation().getStartLine() } - + predicate sameLoc(Element e1, Element e2) { - exists(string name, File f, int startLine | - locInfo(e1, name, f, startLine) and - locInfo(e2, name, f, startLine) - ) + exists(string name, File f, int startLine | + locInfo(e1, name, f, startLine) and + locInfo(e2, name, f, startLine) + ) } Now the structure we want is clearer. We've separated out the easy part into its own predicate ``locInfo``, and the main predicate ``sameLoc`` is just a larger join. From d8f31068d5b2c5ea4fdf1fec6763daa0bfdd014c Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Fri, 3 Jan 2020 15:55:14 +0000 Subject: [PATCH 017/134] Update docs/language/learn-ql/writing-queries/debugging-queries.rst Co-Authored-By: shati-patel <42641846+shati-patel@users.noreply.github.com> (cherry picked from commit 47f61f3569ec964ecc9e128e7f73fefb422495fd) --- docs/language/learn-ql/writing-queries/debugging-queries.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/writing-queries/debugging-queries.rst b/docs/language/learn-ql/writing-queries/debugging-queries.rst index 7fb578e5aa0..68bb1bae9b7 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -81,7 +81,7 @@ That is, you should define a *base case* that allows the predicate to *bottom ou The query optimizer has special data structures for dealing with `transitive closures `__. If possible, use a transitive closure over a simple recursive predicate, as it is likely to be computed faster. -Folding predicates +Fold predicates ~~~~~~~~~~~~~~~~~~ Sometimes you can assist the query optimizer by "folding" parts of large predicates out into smaller predicates. From b56b10b0d931784ece4de5b576ea98794e5a229d Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 7 Feb 2020 12:46:41 +0100 Subject: [PATCH 018/134] Fix typos in QL language spec (cherry picked from commit c431d474812cf8ec73e1f24b539ecda261ef29e1) --- docs/language/ql-spec/language.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/language/ql-spec/language.rst b/docs/language/ql-spec/language.rst index 7b05a7c91f2..12c09de4d10 100644 --- a/docs/language/ql-spec/language.rst +++ b/docs/language/ql-spec/language.rst @@ -502,7 +502,7 @@ Identifiers are used in following syntactic constructs: simpleId ::= lowerId | upperId modulename ::= simpleId classname ::= upperId - dbasetype ::= atlowerId + dbasetype ::= atLowerId predicateRef ::= (moduleId "::")? literalId predicateName ::= lowerId varname ::= simpleId @@ -1970,11 +1970,11 @@ The complete grammar for QL is as follows: simpleId ::= lowerId | upperId - modulename :: = simpleId + modulename ::= simpleId classname ::= upperId - dbasetype ::= atlowerId + dbasetype ::= atLowerId predicateRef ::= (moduleId "::")? literalId From a460d904346ff8aff2dd6f01e2d52186fd1d04da Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 7 Feb 2020 12:47:14 +0100 Subject: [PATCH 019/134] Remove trailing ; in QL language spec (cherry picked from commit c91815f44dc7203d57d5f3c985c6152c424c492c) --- docs/language/ql-spec/language.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/ql-spec/language.rst b/docs/language/ql-spec/language.rst index 12c09de4d10..31d0bef9c82 100644 --- a/docs/language/ql-spec/language.rst +++ b/docs/language/ql-spec/language.rst @@ -1798,7 +1798,7 @@ The complete grammar for QL is as follows: :: - ql ::= moduleBody ; + ql ::= moduleBody module ::= annotation* "module" modulename "{" moduleBody "}" From 35d81513741282f7d5df78cf05c1e0715c086ccc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Feb 2020 11:19:57 +0100 Subject: [PATCH 020/134] add a few arrary methods to TaintedPath.qll --- .../security/dataflow/TaintedPath.qll | 35 ++++++++++++++++--- .../dataflow/TaintedPathCustomizations.qll | 6 ++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index b46f7d508f7..70662bcf60d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -93,13 +93,38 @@ module TaintedPath { | name = argumentlessMethodName ) - or + ) + or + // array method calls of interest + exists(DataFlow::MethodCallNode mcn, string name | dst = mcn and mcn.calls(src, name) | + // A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string. name = "split" and - not exists(DataFlow::Node splitBy | splitBy = mcn.getArgument(0) | - splitBy.mayHaveStringValue("/") or - any(DataFlow::RegExpLiteralNode reg | reg.getRoot().getAMatchedString() = "/") - .flowsTo(splitBy) + ( + if + exists(DataFlow::Node splitBy | splitBy = mcn.getArgument(0) | + splitBy.mayHaveStringValue("/") or + any(DataFlow::RegExpLiteralNode reg | reg.getRoot().getAMatchedString() = "/") + .flowsTo(splitBy) + ) + then + srclabel.(Label::PosixPath).canContainDotDotSlash() and + dstlabel instanceof Label::SplitPath + else srclabel = dstlabel ) + or + ( + name = "pop" or + name = "shift" or + name = "slice" or + name = "splice" + ) and + dstlabel instanceof Label::SplitPath and + srclabel instanceof Label::SplitPath + or + name = "join" and + mcn.getArgument(0).mayHaveStringValue("/") and + srclabel instanceof Label::SplitPath and + dstlabel.(Label::PosixPath).canContainDotDotSlash() ) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 25bb232f8fe..cbb62d7b95d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -108,6 +108,12 @@ module TaintedPath { not (isNormalized() and isAbsolute()) } } + + class SplitPath extends DataFlow::FlowLabel { + SplitPath() { + this = "splitPath" + } + } } /** From 2270c6c960f0fe4ac1ac9a7d086bfb690783fee7 Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 11 Feb 2020 21:45:49 -0800 Subject: [PATCH 021/134] Adds modernized files. --- python/ql/src/Expressions/HashedButNoHash.ql | 2 +- python/ql/src/semmle/python/objects/ObjectAPI.qll | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/src/Expressions/HashedButNoHash.ql b/python/ql/src/Expressions/HashedButNoHash.ql index a654793d458..a28180d799c 100644 --- a/python/ql/src/Expressions/HashedButNoHash.ql +++ b/python/ql/src/Expressions/HashedButNoHash.ql @@ -69,7 +69,7 @@ predicate is_unhashable(ControlFlowNode f, ClassValue cls, ControlFlowNode origi predicate typeerror_is_caught(ControlFlowNode f) { exists (Try try | try.getBody().contains(f.getNode()) and - try.getAHandler().getType().refersTo(theTypeErrorType())) + try.getAHandler().getType().pointsTo(ClassValue::typeErrorType())) } from ControlFlowNode f, ClassValue c, ControlFlowNode origin diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 5fb15229b96..4735001dd68 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -743,6 +743,11 @@ module ClassValue { ClassValue nonetype() { result = TBuiltinClassObject(Builtin::special("NoneType")) } + + /** Get the `ClassValue` for the `TypeError` class */ + ClassValue typeErrorType() { + result = TBuiltinClassObject(Builtin::special("TypeError")) + } /** Get the `ClassValue` for the `NameError` class. */ ClassValue nameError() { From d4c6f487bc88be25adca3f65de9c3db720b61af4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 13 Feb 2020 22:32:52 +0100 Subject: [PATCH 022/134] C++/C#: Fix sync config file for value numbering sharing --- config/identical-files.json | 6 +- .../aliased_ssa/gvn/ValueNumbering.qll | 6 +- .../gvn/internal/ValueNumberingImports.qll | 1 - .../gvn/internal/ValueNumberingInternal.qll | 6 +- .../implementation/raw/gvn/ValueNumbering.qll | 6 +- .../gvn/internal/ValueNumberingImports.qll | 1 - .../gvn/internal/ValueNumberingInternal.qll | 6 +- .../unaliased_ssa/gvn/ValueNumbering.qll | 6 +- .../gvn/internal/ValueNumberingImports.qll | 1 - .../gvn/internal/ValueNumberingInternal.qll | 6 +- .../code/cpp/ir/internal/IRCppLanguage.qll | 4 ++ .../implementation/raw/gvn/ValueNumbering.qll | 6 +- .../gvn/internal/ValueNumberingImports.qll | 2 + .../gvn/internal/ValueNumberingInternal.qll | 72 ++++++++++++++----- .../unaliased_ssa/gvn/ValueNumbering.qll | 6 +- .../gvn/internal/ValueNumberingImports.qll | 2 + .../gvn/internal/ValueNumberingInternal.qll | 36 +++++----- .../csharp/ir/internal/IRCSharpLanguage.qll | 4 ++ 18 files changed, 111 insertions(+), 66 deletions(-) diff --git a/config/identical-files.json b/config/identical-files.json index 0f40aa45a95..47b37455b8c 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -222,10 +222,12 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" ], - "C++ IR ValueNumberInternal": [ + "IR ValueNumberInternal": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll" + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" ], "C++ IR ValueNumber": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll index 1575609fb2f..161f69936e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll @@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber { final Language::Location getLocation() { if exists(Instruction i | - i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation + i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation ) then result = min(Language::Location l | - l = getAnInstruction().getLocation() and not l instanceof UnknownLocation + l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation | l order by l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn() ) - else result instanceof UnknownDefaultLocation + else result instanceof Language::UnknownDefaultLocation } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll index a5f4cfbf32d..8482a5e4b14 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -1,4 +1,3 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.IR import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.IRCppLanguage as Language -import semmle.code.cpp.Location diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll index 28042886742..252bb75a9fa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -1,5 +1,4 @@ private import ValueNumberingImports -private import cpp newtype TValueNumber = TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { @@ -15,7 +14,7 @@ newtype TValueNumber = TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { stringConstantValueNumber(_, irFunc, type, value) } or - TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) { + TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) { fieldAddressValueNumber(_, irFunc, field, objectAddress) } or TBinaryValueNumber( @@ -34,7 +33,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + TValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll index 1575609fb2f..161f69936e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber { final Language::Location getLocation() { if exists(Instruction i | - i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation + i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation ) then result = min(Language::Location l | - l = getAnInstruction().getLocation() and not l instanceof UnknownLocation + l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation | l order by l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn() ) - else result instanceof UnknownDefaultLocation + else result instanceof Language::UnknownDefaultLocation } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll index a5f4cfbf32d..8482a5e4b14 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -1,4 +1,3 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.IR import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.IRCppLanguage as Language -import semmle.code.cpp.Location diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 28042886742..252bb75a9fa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -1,5 +1,4 @@ private import ValueNumberingImports -private import cpp newtype TValueNumber = TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { @@ -15,7 +14,7 @@ newtype TValueNumber = TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { stringConstantValueNumber(_, irFunc, type, value) } or - TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) { + TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) { fieldAddressValueNumber(_, irFunc, field, objectAddress) } or TBinaryValueNumber( @@ -34,7 +33,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + TValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 1575609fb2f..161f69936e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber { final Language::Location getLocation() { if exists(Instruction i | - i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation + i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation ) then result = min(Language::Location l | - l = getAnInstruction().getLocation() and not l instanceof UnknownLocation + l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation | l order by l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn() ) - else result instanceof UnknownDefaultLocation + else result instanceof Language::UnknownDefaultLocation } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll index a5f4cfbf32d..8482a5e4b14 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -1,4 +1,3 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.IR import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.IRCppLanguage as Language -import semmle.code.cpp.Location diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 28042886742..252bb75a9fa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -1,5 +1,4 @@ private import ValueNumberingImports -private import cpp newtype TValueNumber = TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { @@ -15,7 +14,7 @@ newtype TValueNumber = TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { stringConstantValueNumber(_, irFunc, type, value) } or - TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) { + TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) { fieldAddressValueNumber(_, irFunc, field, objectAddress) } or TBinaryValueNumber( @@ -34,7 +33,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + TValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll index 3bde6c7d501..6e88e711711 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll @@ -13,6 +13,10 @@ class Function = Cpp::Function; class Location = Cpp::Location; +class UnknownLocation = Cpp::UnknownLocation; + +class UnknownDefaultLocation = Cpp::UnknownDefaultLocation; + class File = Cpp::File; class AST = Cpp::Locatable; diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll index 1575609fb2f..161f69936e9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber { final Language::Location getLocation() { if exists(Instruction i | - i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation + i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation ) then result = min(Language::Location l | - l = getAnInstruction().getLocation() and not l instanceof UnknownLocation + l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation | l order by l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn() ) - else result instanceof UnknownDefaultLocation + else result instanceof Language::UnknownDefaultLocation } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll index 555cb581d37..a9da238c893 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -1 +1,3 @@ import semmle.code.csharp.ir.internal.Overlap +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import semmle.code.csharp.ir.implementation.unaliased_ssa.IR \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 9408469a867..252bb75a9fa 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -1,17 +1,10 @@ private import ValueNumberingImports -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.Location - -class UnknownLocation = EmptyLocation; - -class UnknownDefaultLocation = EmptyLocation; newtype TValueNumber = - TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) { - variableAddressValueNumber(_, irFunc, var) + TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { + variableAddressValueNumber(_, irFunc, ast) } or - TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) { + TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or @@ -45,6 +38,11 @@ newtype TValueNumber = ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or + TLoadTotalOverlapValueNumber( + IRFunction irFunc, IRType type, TValueNumber memOperand, TValueNumber operand + ) { + loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand) + } or TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } /** @@ -61,12 +59,18 @@ newtype TValueNumber = * The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not * congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`. */ -private class CongruentCopyInstruction extends CopyInstruction { +class CongruentCopyInstruction extends CopyInstruction { CongruentCopyInstruction() { this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap } } +class LoadTotalOverlapInstruction extends LoadInstruction { + LoadTotalOverlapInstruction() { + this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap + } +} + /** * Holds if this library knows how to assign a value number to the specified instruction, other than * a `unique` value number that is never shared by multiple instructions. @@ -91,20 +95,28 @@ private predicate numberableInstruction(Instruction instr) { instr instanceof PointerArithmeticInstruction or instr instanceof CongruentCopyInstruction + or + instr instanceof LoadTotalOverlapInstruction } private predicate variableAddressValueNumber( - VariableAddressInstruction instr, IRFunction irFunc, IRVariable var + VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast ) { instr.getEnclosingIRFunction() = irFunc and - instr.getIRVariable() = var + // The underlying AST element is used as value-numbering key instead of the + // `IRVariable` to work around a problem where a variable or expression with + // multiple types gives rise to multiple `IRVariable`s. + instr.getIRVariable().getAST() = ast } private predicate initializeParameterValueNumber( - InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var + InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getIRVariable() = var + // The underlying AST element is used as value-numbering key instead of the + // `IRVariable` to work around a problem where a variable or expression with + // multiple types gives rise to multiple `IRVariable`s. + instr.getIRVariable().getAST() = var } private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { @@ -166,6 +178,7 @@ private predicate unaryValueNumber( instr.getEnclosingIRFunction() = irFunc and not instr instanceof InheritanceConversionInstruction and not instr instanceof CopyInstruction and + not instr instanceof FieldAddressInstruction and instr.getOpcode() = opcode and instr.getResultIRType() = type and tvalueNumber(instr.getUnary()) = operand @@ -182,6 +195,16 @@ private predicate inheritanceConversionValueNumber( tvalueNumber(instr.getUnary()) = operand } +private predicate loadTotalOverlapValueNumber( + LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand, + TValueNumber operand +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getResultIRType() = type and + tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and + tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand +} + /** * Holds if `instr` should be assigned a unique value number because this library does not know how * to determine if two instances of that instruction are equivalent. @@ -205,6 +228,12 @@ TValueNumber tvalueNumber(Instruction instr) { ) } +/** + * Gets the value number assigned to the exact definition of `op`, if any. + * Returns at most one result. + */ +TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef()) } + /** * Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique * value number. @@ -213,12 +242,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() and ( - exists(IRVariable var | - variableAddressValueNumber(instr, irFunc, var) and - result = TVariableAddressValueNumber(irFunc, var) + exists(Language::AST ast | + variableAddressValueNumber(instr, irFunc, ast) and + result = TVariableAddressValueNumber(irFunc, ast) ) or - exists(IRVariable var | + exists(Language::AST var | initializeParameterValueNumber(instr, irFunc, var) and result = TInitializeParameterValueNumber(irFunc, var) ) @@ -268,6 +297,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand) ) or + exists(IRType type, TValueNumber memOperand, TValueNumber operand | + loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and + result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand) + ) + or // The value number of a copy is just the value number of its source value. result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue()) ) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 1575609fb2f..161f69936e9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber { final Language::Location getLocation() { if exists(Instruction i | - i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation + i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation ) then result = min(Language::Location l | - l = getAnInstruction().getLocation() and not l instanceof UnknownLocation + l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation | l order by l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn() ) - else result instanceof UnknownDefaultLocation + else result instanceof Language::UnknownDefaultLocation } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll index 555cb581d37..a9da238c893 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -1 +1,3 @@ import semmle.code.csharp.ir.internal.Overlap +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import semmle.code.csharp.ir.implementation.unaliased_ssa.IR \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index fc0177a2e2c..252bb75a9fa 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -1,17 +1,10 @@ private import ValueNumberingImports -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR -private import semmle.code.csharp.Location - -class UnknownLocation = EmptyLocation; - -class UnknownDefaultLocation = EmptyLocation; newtype TValueNumber = - TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) { - variableAddressValueNumber(_, irFunc, var) + TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { + variableAddressValueNumber(_, irFunc, ast) } or - TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) { + TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or @@ -107,17 +100,23 @@ private predicate numberableInstruction(Instruction instr) { } private predicate variableAddressValueNumber( - VariableAddressInstruction instr, IRFunction irFunc, IRVariable var + VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast ) { instr.getEnclosingIRFunction() = irFunc and - instr.getIRVariable() = var + // The underlying AST element is used as value-numbering key instead of the + // `IRVariable` to work around a problem where a variable or expression with + // multiple types gives rise to multiple `IRVariable`s. + instr.getIRVariable().getAST() = ast } private predicate initializeParameterValueNumber( - InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var + InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getIRVariable() = var + // The underlying AST element is used as value-numbering key instead of the + // `IRVariable` to work around a problem where a variable or expression with + // multiple types gives rise to multiple `IRVariable`s. + instr.getIRVariable().getAST() = var } private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { @@ -179,6 +178,7 @@ private predicate unaryValueNumber( instr.getEnclosingIRFunction() = irFunc and not instr instanceof InheritanceConversionInstruction and not instr instanceof CopyInstruction and + not instr instanceof FieldAddressInstruction and instr.getOpcode() = opcode and instr.getResultIRType() = type and tvalueNumber(instr.getUnary()) = operand @@ -242,12 +242,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() and ( - exists(IRVariable var | - variableAddressValueNumber(instr, irFunc, var) and - result = TVariableAddressValueNumber(irFunc, var) + exists(Language::AST ast | + variableAddressValueNumber(instr, irFunc, ast) and + result = TVariableAddressValueNumber(irFunc, ast) ) or - exists(IRVariable var | + exists(Language::AST var | initializeParameterValueNumber(instr, irFunc, var) and result = TInitializeParameterValueNumber(irFunc, var) ) diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll index cd4e96a25a3..a8fb448f8d0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll @@ -10,6 +10,10 @@ class Function = CSharp::Callable; class Location = CSharp::Location; +class UnknownLocation = CSharp::EmptyLocation; + +class UnknownDefaultLocation = CSharp::EmptyLocation; + class File = CSharp::File; class AST = CSharp::Element; From 98db6d8fd7495d97136eb2477ac75a3c224bab3a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 14 Feb 2020 08:22:25 +0100 Subject: [PATCH 023/134] C#: Fix format and sync files --- .../implementation/raw/gvn/internal/ValueNumberingImports.qll | 2 +- .../unaliased_ssa/gvn/internal/ValueNumberingImports.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll index a9da238c893..3d200900445 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -1,3 +1,3 @@ import semmle.code.csharp.ir.internal.Overlap import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR \ No newline at end of file +import semmle.code.csharp.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll index a9da238c893..3d200900445 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -1,3 +1,3 @@ import semmle.code.csharp.ir.internal.Overlap import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR \ No newline at end of file +import semmle.code.csharp.ir.implementation.unaliased_ssa.IR From 3a146514cea911df2906d717e2dc3cc6860f874b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 13 Feb 2020 18:44:02 +0100 Subject: [PATCH 024/134] add sanitizer for relative ".." in js/path-injection --- .../security/dataflow/TaintedPath.qll | 3 +- .../dataflow/TaintedPathCustomizations.qll | 43 +++++++++--- .../CWE-022/TaintedPath/TaintedPath.expected | 67 +++++++++++++++++++ .../CWE-022/TaintedPath/normalizedPaths.js | 23 +++++++ 4 files changed, 126 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index b46f7d508f7..c72257b47c0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -35,7 +35,8 @@ module TaintedPath { guard instanceof StartsWithDotDotSanitizer or guard instanceof StartsWithDirSanitizer or guard instanceof IsAbsoluteSanitizer or - guard instanceof ContainsDotDotSanitizer + guard instanceof ContainsDotDotSanitizer or + guard instanceof RelativePathContainsDotDotGuard } override predicate isAdditionalFlowStep( diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 25bb232f8fe..4c5037b56dd 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -12,19 +12,17 @@ module TaintedPath { */ abstract class Source extends DataFlow::Node { /** Gets a flow label denoting the type of value for which this is a source. */ - DataFlow::FlowLabel getAFlowLabel() { - result instanceof Label::PosixPath - } + DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::PosixPath } } /** * A data flow sink for tainted-path vulnerabilities. */ abstract class Sink extends DataFlow::Node { + Sink() { not this instanceof Sanitizer } + /** Gets a flow label denoting the type of value for which this is a sink. */ - DataFlow::FlowLabel getAFlowLabel() { - result instanceof Label::PosixPath - } + DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::PosixPath } } /** @@ -355,6 +353,35 @@ module TaintedPath { } } + /** + * A sanitizer that recognizes the following pattern: + * var relative = path.relative(webroot, pathname); + * if(relative.startsWith(".." + path.sep) || relative == "..") { + * // pathname is unsafe + * } else { + * // pathname is safe + * } + */ + class RelativePathContainsDotDotGuard extends DataFlow::BarrierGuardNode { + StringOps::StartsWith startsWith; + DataFlow::CallNode relativeCall; + + RelativePathContainsDotDotGuard() { + this = startsWith and + relativeCall = DataFlow::moduleImport("path").getAMemberCall("relative") and + startsWith.getBaseString().getALocalSource() = relativeCall and + exists(DataFlow::Node subString | subString = startsWith.getSubstring() | + subString.mayHaveStringValue("..") + or + subString.(StringOps::ConcatenationRoot).getFirstLeaf().mayHaveStringValue("..") + ) + } + + override predicate blocks(boolean outcome, Expr e) { + e = relativeCall.getArgument(1).asExpr() and outcome = false + } + } + /** * A source of remote user input, considered as a flow source for * tainted-path vulnerabilities. @@ -396,9 +423,7 @@ module TaintedPath { * A path argument to a file system access, which disallows upward navigation. */ private class FsPathSinkWithoutUpwardNavigation extends FsPathSink { - FsPathSinkWithoutUpwardNavigation() { - fileSystemAccess.isUpwardNavigationRejected(this) - } + FsPathSinkWithoutUpwardNavigation() { fileSystemAccess.isUpwardNavigationRejected(this) } override DataFlow::FlowLabel getAFlowLabel() { // The protection is ineffective if the ../ segments have already diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 7e2aa30fe1f..650c2ed9440 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1259,6 +1259,34 @@ nodes | normalizedPaths.js:250:21:250:24 | path | | normalizedPaths.js:250:21:250:24 | path | | normalizedPaths.js:250:21:250:24 | path | +| normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | +| normalizedPaths.js:254:33:254:46 | req.query.path | +| normalizedPaths.js:254:33:254:46 | req.query.path | +| normalizedPaths.js:254:33:254:46 | req.query.path | +| normalizedPaths.js:254:33:254:46 | req.query.path | +| normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:270:21:270:24 | path | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -3630,6 +3658,42 @@ edges | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:236:14:236:47 | pathMod ... y.path) | | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:236:14:236:47 | pathMod ... y.path) | | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:236:14:236:47 | pathMod ... y.path) | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:256:19:256:22 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -4411,6 +4475,9 @@ edges | normalizedPaths.js:238:19:238:22 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:238:19:238:22 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | | normalizedPaths.js:245:21:245:24 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:245:21:245:24 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | | normalizedPaths.js:250:21:250:24 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:250:21:250:24 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | +| normalizedPaths.js:256:19:256:22 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:256:19:256:22 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | +| normalizedPaths.js:262:21:262:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:262:21:262:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | +| normalizedPaths.js:270:21:270:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:270:21:270:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js index c0be777dd84..121ac5e8e63 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js @@ -249,3 +249,26 @@ app.get('/resolve-path', (req, res) => { else fs.readFileSync(path); // NOT OK - wrong polarity }); + +app.get('/relative-startswith', (req, res) => { + let path = pathModule.resolve(req.query.path); + + fs.readFileSync(path); // NOT OK + + var self = something(); + + var relative = pathModule.relative(self.webroot, path); + if(relative.startsWith(".." + pathModule.sep) || relative == "..") { + fs.readFileSync(path); // NOT OK! + } else { + fs.readFileSync(path); // OK! + } + + let newpath = pathModule.normalize(p); + var relativePath = path.relative(path.normalize(workspaceDir), newpath); + if (relativePath.indexOf('..' + pathModule.sep) === 0) { + fs.readFileSync(path); // NOT OK! + } else { + fs.readFileSync(newpath); // OK! + } +}); From 9d610041281c7373c95b56d03aeaadae3d1c0c98 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 14 Feb 2020 12:31:12 +0100 Subject: [PATCH 025/134] remove redundant constructor on sink --- .../javascript/security/dataflow/TaintedPathCustomizations.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 4c5037b56dd..00b6790c6d0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -19,8 +19,6 @@ module TaintedPath { * A data flow sink for tainted-path vulnerabilities. */ abstract class Sink extends DataFlow::Node { - Sink() { not this instanceof Sanitizer } - /** Gets a flow label denoting the type of value for which this is a sink. */ DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::PosixPath } } From d765a33b8dc9e64e72303bcb1d63a72a2881b411 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 14 Feb 2020 12:36:54 +0100 Subject: [PATCH 026/134] add support for "../" prefixes in sanitizer --- .../dataflow/TaintedPathCustomizations.qll | 9 ++++++--- .../CWE-022/TaintedPath/TaintedPath.expected | 14 ++++++++++++++ .../CWE-022/TaintedPath/normalizedPaths.js | 10 +++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 00b6790c6d0..38b06e06f14 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -368,10 +368,13 @@ module TaintedPath { this = startsWith and relativeCall = DataFlow::moduleImport("path").getAMemberCall("relative") and startsWith.getBaseString().getALocalSource() = relativeCall and - exists(DataFlow::Node subString | subString = startsWith.getSubstring() | - subString.mayHaveStringValue("..") + exists(DataFlow::Node subString, string prefix | + subString = startsWith.getSubstring() and + (prefix = ".." or prefix = "../") + | + subString.mayHaveStringValue(prefix) or - subString.(StringOps::ConcatenationRoot).getFirstLeaf().mayHaveStringValue("..") + subString.(StringOps::ConcatenationRoot).getFirstLeaf().mayHaveStringValue(prefix) ) } diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 650c2ed9440..856aeb014ce 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1287,6 +1287,11 @@ nodes | normalizedPaths.js:270:21:270:24 | path | | normalizedPaths.js:270:21:270:24 | path | | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:278:21:278:24 | path | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -3682,6 +3687,14 @@ edges | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | @@ -4478,6 +4491,7 @@ edges | normalizedPaths.js:256:19:256:22 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:256:19:256:22 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | normalizedPaths.js:262:21:262:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:262:21:262:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | normalizedPaths.js:270:21:270:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:270:21:270:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | +| normalizedPaths.js:278:21:278:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:278:21:278:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js index 121ac5e8e63..29a682b8d1e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js @@ -269,6 +269,14 @@ app.get('/relative-startswith', (req, res) => { if (relativePath.indexOf('..' + pathModule.sep) === 0) { fs.readFileSync(path); // NOT OK! } else { - fs.readFileSync(newpath); // OK! + fs.readFileSync(newpath); // OK! + } + + let newpath = pathModule.normalize(p); + var relativePath = path.relative(path.normalize(workspaceDir), newpath); + if (relativePath.indexOf('../') === 0) { + fs.readFileSync(path); // NOT OK! + } else { + fs.readFileSync(newpath); // OK! } }); From 94814fa72193e36c20db6b021ebfa6793f89c2c8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 14 Feb 2020 13:03:04 +0100 Subject: [PATCH 027/134] fix typos in the test --- .../CWE-022/TaintedPath/TaintedPath.expected | 104 +++++++++++++----- .../CWE-022/TaintedPath/normalizedPaths.js | 12 +- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 856aeb014ce..ffe143fc423 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1282,16 +1282,40 @@ nodes | normalizedPaths.js:262:21:262:24 | path | | normalizedPaths.js:262:21:262:24 | path | | normalizedPaths.js:262:21:262:24 | path | -| normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:278:21:278:27 | newpath | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -3679,22 +3703,14 @@ edges | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:262:21:262:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:270:21:270:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | -| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:278:21:278:24 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:267:38:267:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:275:38:275:41 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | @@ -3707,6 +3723,38 @@ edges | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:7:267:42 | newpath | normalizedPaths.js:270:21:270:27 | newpath | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | normalizedPaths.js:267:7:267:42 | newpath | +| normalizedPaths.js:267:38:267:41 | path | normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:267:38:267:41 | path | normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:267:38:267:41 | path | normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:267:38:267:41 | path | normalizedPaths.js:267:17:267:42 | pathMod ... e(path) | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:7:275:42 | newpath | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | normalizedPaths.js:275:7:275:42 | newpath | +| normalizedPaths.js:275:38:275:41 | path | normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:275:38:275:41 | path | normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:275:38:275:41 | path | normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:275:38:275:41 | path | normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -4490,8 +4538,8 @@ edges | normalizedPaths.js:250:21:250:24 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:250:21:250:24 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | | normalizedPaths.js:256:19:256:22 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:256:19:256:22 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | normalizedPaths.js:262:21:262:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:262:21:262:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | -| normalizedPaths.js:270:21:270:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:270:21:270:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | -| normalizedPaths.js:278:21:278:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:278:21:278:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | +| normalizedPaths.js:270:21:270:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:270:21:270:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | +| normalizedPaths.js:278:21:278:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:278:21:278:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js index 29a682b8d1e..6248f41e66b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js @@ -264,18 +264,18 @@ app.get('/relative-startswith', (req, res) => { fs.readFileSync(path); // OK! } - let newpath = pathModule.normalize(p); - var relativePath = path.relative(path.normalize(workspaceDir), newpath); + let newpath = pathModule.normalize(path); + var relativePath = pathModule.relative(pathModule.normalize(workspaceDir), newpath); if (relativePath.indexOf('..' + pathModule.sep) === 0) { - fs.readFileSync(path); // NOT OK! + fs.readFileSync(newpath); // NOT OK! } else { fs.readFileSync(newpath); // OK! } - let newpath = pathModule.normalize(p); - var relativePath = path.relative(path.normalize(workspaceDir), newpath); + let newpath = pathModule.normalize(path); + var relativePath = pathModule.relative(pathModule.normalize(workspaceDir), newpath); if (relativePath.indexOf('../') === 0) { - fs.readFileSync(path); // NOT OK! + fs.readFileSync(newpath); // NOT OK! } else { fs.readFileSync(newpath); // OK! } From a6d644bac09fbc30df4c09aaf6a3cb8f72662eb0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 14 Feb 2020 13:10:35 +0100 Subject: [PATCH 028/134] add support for path.normalize(path.realtive(...)) --- .../dataflow/TaintedPathCustomizations.qll | 11 +++++- .../CWE-022/TaintedPath/TaintedPath.expected | 38 +++++++++++++++++++ .../CWE-022/TaintedPath/normalizedPaths.js | 8 ++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 38b06e06f14..fc8ac5b1a84 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -367,7 +367,16 @@ module TaintedPath { RelativePathContainsDotDotGuard() { this = startsWith and relativeCall = DataFlow::moduleImport("path").getAMemberCall("relative") and - startsWith.getBaseString().getALocalSource() = relativeCall and + ( + startsWith.getBaseString().getALocalSource() = relativeCall + or + startsWith + .getBaseString() + .getALocalSource() + .(NormalizingPathCall) + .getInput() + .getALocalSource() = relativeCall + ) and exists(DataFlow::Node subString, string prefix | subString = startsWith.getSubstring() and (prefix = ".." or prefix = "../") diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index ffe143fc423..ab0869ca257 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1316,6 +1316,23 @@ nodes | normalizedPaths.js:278:21:278:27 | newpath | | normalizedPaths.js:278:21:278:27 | newpath | | normalizedPaths.js:278:21:278:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:286:21:286:27 | newpath | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -3711,6 +3728,10 @@ edges | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:275:38:275:41 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:275:38:275:41 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:275:38:275:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:283:38:283:41 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | @@ -3755,6 +3776,22 @@ edges | normalizedPaths.js:275:38:275:41 | path | normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | | normalizedPaths.js:275:38:275:41 | path | normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | | normalizedPaths.js:275:38:275:41 | path | normalizedPaths.js:275:17:275:42 | pathMod ... e(path) | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:7:283:42 | newpath | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | normalizedPaths.js:283:7:283:42 | newpath | +| normalizedPaths.js:283:38:283:41 | path | normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:283:38:283:41 | path | normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:283:38:283:41 | path | normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:283:38:283:41 | path | normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -4540,6 +4577,7 @@ edges | normalizedPaths.js:262:21:262:24 | path | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:262:21:262:24 | path | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | normalizedPaths.js:270:21:270:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:270:21:270:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | normalizedPaths.js:278:21:278:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:278:21:278:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | +| normalizedPaths.js:286:21:286:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:286:21:286:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js index 6248f41e66b..c718d9075c6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js @@ -279,4 +279,12 @@ app.get('/relative-startswith', (req, res) => { } else { fs.readFileSync(newpath); // OK! } + + let newpath = pathModule.normalize(path); + var relativePath = pathModule.relative(pathModule.normalize(workspaceDir), newpath); + if (pathModule.normalize(relativePath).indexOf('../') === 0) { + fs.readFileSync(newpath); // NOT OK! + } else { + fs.readFileSync(newpath); // OK! + } }); From 46cbeb0bc6580aa9f7873ae2ed90d6eeab4c1408 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Feb 2020 12:58:27 +0100 Subject: [PATCH 029/134] add more steps to the SplitPath label --- .../security/dataflow/TaintedPath.qll | 29 +- .../CWE-022/TaintedPath/TaintedPath.expected | 649 ++++++++++++++++++ .../CWE-022/TaintedPath/TaintedPath.js | 22 + .../TaintedPath/tainted-string-steps.js | 7 +- 4 files changed, 702 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index 70662bcf60d..d417440e5ab 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -116,13 +116,38 @@ module TaintedPath { name = "pop" or name = "shift" or name = "slice" or - name = "splice" + name = "splice" or + name = "concat" ) and dstlabel instanceof Label::SplitPath and srclabel instanceof Label::SplitPath or name = "join" and - mcn.getArgument(0).mayHaveStringValue("/") and + mcn.getArgument(0).mayHaveStringValue("/") and + srclabel instanceof Label::SplitPath and + dstlabel.(Label::PosixPath).canContainDotDotSlash() + ) + or + // prefix.concat(path) + exists(DataFlow::MethodCallNode mcn | + mcn.getMethodName() = "concat" and mcn.getAnArgument() = src + | + dst = mcn and + dstlabel instanceof Label::SplitPath and + srclabel instanceof Label::SplitPath + ) + or + // reading unknown property of split path + exists(DataFlow::PropRead read | read = dst | + src = read.getBase() and + not read.getPropertyName() = "length" and + not exists(read.getPropertyNameExpr().getIntValue()) and + // split[split.length - 1] + not exists(BinaryExpr binop | + read.getPropertyNameExpr() = binop and + binop.getAnOperand().getIntValue() = 1 and + binop.getAnOperand().(PropAccess).getPropertyName() = "length" + ) and srclabel instanceof Label::SplitPath and dstlabel.(Label::PosixPath).canContainDotDotSlash() ) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 7e2aa30fe1f..46d124eaeae 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -887,6 +887,225 @@ nodes | TaintedPath.js:121:23:121:26 | path | | TaintedPath.js:121:23:121:26 | path | | TaintedPath.js:121:23:121:26 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:24:126:30 | req.url | +| TaintedPath.js:126:24:126:30 | req.url | +| TaintedPath.js:126:24:126:30 | req.url | +| TaintedPath.js:126:24:126:30 | req.url | +| TaintedPath.js:126:24:126:30 | req.url | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | | normalizedPaths.js:11:7:11:27 | path | | normalizedPaths.js:11:7:11:27 | path | | normalizedPaths.js:11:7:11:27 | path | @@ -1631,6 +1850,64 @@ nodes | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:24:18:24:21 | path | | tainted-string-steps.js:24:18:24:21 | path | | tainted-string-steps.js:24:18:24:21 | path | @@ -3194,6 +3471,290 @@ edges | TaintedPath.js:119:23:119:29 | req.url | TaintedPath.js:119:13:119:36 | url.par ... , true) | | TaintedPath.js:119:23:119:29 | req.url | TaintedPath.js:119:13:119:36 | url.par ... , true) | | TaintedPath.js:119:23:119:29 | req.url | TaintedPath.js:119:13:119:36 | url.par ... , true) | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:128:19:128:22 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:7:126:48 | path | TaintedPath.js:130:15:130:18 | path | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:37 | url.par ... , true) | TaintedPath.js:126:14:126:43 | url.par ... ).query | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:43 | url.par ... ).query | TaintedPath.js:126:14:126:48 | url.par ... ry.path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:14:126:48 | url.par ... ry.path | TaintedPath.js:126:7:126:48 | path | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:126:14:126:37 | url.par ... , true) | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:132:19:132:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:136:19:136:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:137:28:137:32 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:139:33:139:37 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | +| TaintedPath.js:130:15:130:29 | path.split("/") | TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:130:15:130:29 | path.split("/") | TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:130:15:130:29 | path.split("/") | TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:130:15:130:29 | path.split("/") | TaintedPath.js:130:7:130:29 | split | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:132:19:132:23 | split | TaintedPath.js:132:19:132:33 | split.join("/") | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:136:19:136:23 | split | TaintedPath.js:136:19:136:26 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:32 | split | TaintedPath.js:137:28:137:35 | split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:137:28:137:35 | split[x] | TaintedPath.js:137:19:137:35 | prefix + split[x] | +| TaintedPath.js:139:7:139:38 | concatted | TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:139:7:139:38 | concatted | TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:139:7:139:38 | concatted | TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:139:7:139:38 | concatted | TaintedPath.js:140:19:140:27 | concatted | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:19:139:38 | prefix.concat(split) | TaintedPath.js:139:7:139:38 | concatted | +| TaintedPath.js:139:33:139:37 | split | TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:139:33:139:37 | split | TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:139:33:139:37 | split | TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:139:33:139:37 | split | TaintedPath.js:139:19:139:38 | prefix.concat(split) | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:140:19:140:27 | concatted | TaintedPath.js:140:19:140:37 | concatted.join("/") | +| TaintedPath.js:142:7:142:39 | concatted2 | TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:142:7:142:39 | concatted2 | TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:142:7:142:39 | concatted2 | TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:142:7:142:39 | concatted2 | TaintedPath.js:143:19:143:28 | concatted2 | +| TaintedPath.js:142:20:142:24 | split | TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:142:20:142:24 | split | TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:142:20:142:24 | split | TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:142:20:142:24 | split | TaintedPath.js:142:20:142:39 | split.concat(prefix) | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:142:20:142:39 | split.concat(prefix) | TaintedPath.js:142:7:142:39 | concatted2 | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | @@ -3793,6 +4354,30 @@ edges | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | @@ -4193,6 +4778,62 @@ edges | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | @@ -4370,6 +5011,12 @@ edges | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | This path depends on $@. | TaintedPath.js:107:23:107:29 | req.url | a user-provided value | | TaintedPath.js:112:45:112:52 | realpath | TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:112:45:112:52 | realpath | This path depends on $@. | TaintedPath.js:107:23:107:29 | req.url | a user-provided value | | TaintedPath.js:121:23:121:26 | path | TaintedPath.js:119:23:119:29 | req.url | TaintedPath.js:121:23:121:26 | path | This path depends on $@. | TaintedPath.js:119:23:119:29 | req.url | a user-provided value | +| TaintedPath.js:128:19:128:22 | path | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:128:19:128:22 | path | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | +| TaintedPath.js:132:19:132:33 | split.join("/") | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:132:19:132:33 | split.join("/") | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | +| TaintedPath.js:136:19:136:26 | split[x] | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:136:19:136:26 | split[x] | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | +| TaintedPath.js:137:19:137:35 | prefix + split[x] | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:137:19:137:35 | prefix + split[x] | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | +| TaintedPath.js:140:19:140:37 | concatted.join("/") | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:140:19:140:37 | concatted.join("/") | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | +| TaintedPath.js:143:19:143:38 | concatted2.join("/") | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:143:19:143:38 | concatted2.join("/") | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | | normalizedPaths.js:13:19:13:22 | path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:13:19:13:22 | path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | | normalizedPaths.js:14:19:14:29 | './' + path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:14:19:14:29 | './' + path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | | normalizedPaths.js:15:19:15:38 | path + '/index.html' | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:15:19:15:38 | path + '/index.html' | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | @@ -4426,6 +5073,8 @@ edges | tainted-string-steps.js:15:18:15:46 | unknown ... , path) | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:15:18:15:46 | unknown ... , path) | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | | tainted-string-steps.js:17:18:17:28 | path.trim() | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:17:18:17:28 | path.trim() | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | +| tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | +| tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js index 36604536686..4044e16a34d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js @@ -121,3 +121,25 @@ var server = http.createServer(function(req, res) { require('send')(req, path); // NOT OK }); + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + fs.readFileSync(path); // NOT OK + + var split = path.split("/"); + + fs.readFileSync(split.join("/")); // NOT OK + + fs.readFileSync(prefix + split[split.length - 1]) // OK + + fs.readFileSync(split[x]) // NOT OK + fs.readFileSync(prefix + split[x]) // NOT OK + + var concatted = prefix.concat(split); + fs.readFileSync(concatted.join("/")); // NOT OK + + var concatted2 = split.concat(prefix); + fs.readFileSync(concatted2.join("/")); // NOT OK + +}); \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js index d61f650d388..aa56b191465 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js @@ -17,14 +17,15 @@ var server = http.createServer(function(req, res) { fs.readFileSync(path.trim()); // NOT OK fs.readFileSync(path.toLowerCase()); // NOT OK - fs.readFileSync(path.split('/')); // OK -- for now + fs.readFileSync(path.split('/')); // OK (readFile throws an exception when the filename is an array) fs.readFileSync(path.split('/')[0]); // OK -- for now - fs.readFileSync(path.split('/')[i]); // OK -- for now - fs.readFileSync(path.split(/\//)[i]); // OK -- for now + fs.readFileSync(path.split('/')[i]); // NOT OK + fs.readFileSync(path.split(/\//)[i]); // NOT OK fs.readFileSync(path.split("?")[0]); // NOT OK fs.readFileSync(path.split(unknown)[i]); // NOT OK -- but not yet flagged fs.readFileSync(path.split(unknown).whatever); // OK -- but still flagged fs.readFileSync(path.split(unknown)); // NOT OK + fs.readFileSync(path.split("?")[i]); // NOT OK -- but not yet flagged }); server.listen(); From 3855268201e0081769fd5fc5418ed7bc1a39219f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Feb 2020 13:02:47 +0100 Subject: [PATCH 030/134] use RegExpCreationNode --- .../ql/src/semmle/javascript/security/dataflow/TaintedPath.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index d417440e5ab..4ff45dfc4cf 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -103,7 +103,7 @@ module TaintedPath { if exists(DataFlow::Node splitBy | splitBy = mcn.getArgument(0) | splitBy.mayHaveStringValue("/") or - any(DataFlow::RegExpLiteralNode reg | reg.getRoot().getAMatchedString() = "/") + any(DataFlow::RegExpCreationNode reg | reg.getRoot().getAMatchedString() = "/") .flowsTo(splitBy) ) then From c5ee436b16c7452d565028e82ab25ad2fb0d0cf1 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 17 Feb 2020 12:02:29 +0100 Subject: [PATCH 031/134] JS: add RegExp::getSuccessor/getPredecessor tests --- .../getPredecessor.expected | 42 +++++++++++++++++++ .../getPredecessor.ql | 5 +++ .../getSuccessor.expected | 38 +++++++++++++++++ .../getSuccessor.ql | 5 +++ .../RegExp/predecessors_and_successors/tst.js | 17 ++++++++ 5 files changed, 107 insertions(+) create mode 100644 javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected create mode 100644 javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.ql create mode 100644 javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected create mode 100644 javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.ql create mode 100644 javascript/ql/test/library-tests/RegExp/predecessors_and_successors/tst.js diff --git a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected new file mode 100644 index 00000000000..4758562cf3c --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected @@ -0,0 +1,42 @@ +| tst.js:2:2:2:2 | a | tst.js:2:3:2:5 | (b) | +| tst.js:2:2:2:2 | a | tst.js:2:4:2:4 | b | +| tst.js:3:2:3:3 | ab | tst.js:3:4:3:6 | (c) | +| tst.js:3:2:3:3 | ab | tst.js:3:5:3:5 | c | +| tst.js:4:2:4:2 | a | tst.js:4:3:4:6 | (bc) | +| tst.js:4:2:4:2 | a | tst.js:4:4:4:5 | bc | +| tst.js:5:2:5:2 | a | tst.js:5:3:5:8 | (b[c]) | +| tst.js:5:2:5:2 | a | tst.js:5:4:5:4 | b | +| tst.js:5:2:5:2 | a | tst.js:5:4:5:7 | b[c] | +| tst.js:5:2:5:2 | a | tst.js:5:5:5:7 | [c] | +| tst.js:5:2:5:2 | a | tst.js:5:6:5:6 | c | +| tst.js:5:4:5:4 | b | tst.js:5:5:5:7 | [c] | +| tst.js:5:4:5:4 | b | tst.js:5:6:5:6 | c | +| tst.js:6:2:6:2 | a | tst.js:6:3:6:9 | (b\|[b]) | +| tst.js:6:2:6:2 | a | tst.js:6:4:6:4 | b | +| tst.js:6:2:6:2 | a | tst.js:6:4:6:8 | b\|[b] | +| tst.js:6:2:6:2 | a | tst.js:6:6:6:8 | [b] | +| tst.js:6:2:6:2 | a | tst.js:6:7:6:7 | b | +| tst.js:7:2:7:2 | a | tst.js:7:3:7:10 | ([b][c]) | +| tst.js:7:2:7:2 | a | tst.js:7:4:7:6 | [b] | +| tst.js:7:2:7:2 | a | tst.js:7:4:7:9 | [b][c] | +| tst.js:7:2:7:2 | a | tst.js:7:5:7:5 | b | +| tst.js:7:2:7:2 | a | tst.js:7:7:7:9 | [c] | +| tst.js:7:2:7:2 | a | tst.js:7:8:7:8 | c | +| tst.js:7:4:7:6 | [b] | tst.js:7:7:7:9 | [c] | +| tst.js:7:4:7:6 | [b] | tst.js:7:8:7:8 | c | +| tst.js:8:2:8:2 | a | tst.js:8:3:8:13 | (b\|[b]\|[b]) | +| tst.js:8:2:8:2 | a | tst.js:8:4:8:4 | b | +| tst.js:8:2:8:2 | a | tst.js:8:4:8:12 | b\|[b]\|[b] | +| tst.js:8:2:8:2 | a | tst.js:8:6:8:8 | [b] | +| tst.js:8:2:8:2 | a | tst.js:8:7:8:7 | b | +| tst.js:8:2:8:2 | a | tst.js:8:10:8:12 | [b] | +| tst.js:8:2:8:2 | a | tst.js:8:11:8:11 | b | +| tst.js:11:2:11:4 | (a) | tst.js:11:5:11:5 | b | +| tst.js:12:2:12:4 | (a) | tst.js:12:5:12:6 | bc | +| tst.js:13:2:13:5 | (ab) | tst.js:13:6:13:6 | c | +| tst.js:14:2:14:7 | ([a]b) | tst.js:14:8:14:8 | c | +| tst.js:14:3:14:5 | [a] | tst.js:14:6:14:6 | b | +| tst.js:16:2:16:9 | ([a][b]) | tst.js:16:10:16:10 | c | +| tst.js:16:3:16:5 | [a] | tst.js:16:6:16:8 | [b] | +| tst.js:16:3:16:5 | [a] | tst.js:16:7:16:7 | b | +| tst.js:17:2:17:12 | ([a]\|[a]\|a) | tst.js:17:13:17:13 | b | diff --git a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.ql b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.ql new file mode 100644 index 00000000000..c356564dc7f --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.ql @@ -0,0 +1,5 @@ +import javascript + +from RegExpTerm pred, RegExpTerm succ +where pred = succ.getPredecessor() +select pred, succ \ No newline at end of file diff --git a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected new file mode 100644 index 00000000000..60ba52bb03c --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected @@ -0,0 +1,38 @@ +| tst.js:2:2:2:2 | a | tst.js:2:3:2:5 | (b) | +| tst.js:3:2:3:3 | ab | tst.js:3:4:3:6 | (c) | +| tst.js:4:2:4:2 | a | tst.js:4:3:4:6 | (bc) | +| tst.js:5:2:5:2 | a | tst.js:5:3:5:8 | (b[c]) | +| tst.js:5:4:5:4 | b | tst.js:5:5:5:7 | [c] | +| tst.js:6:2:6:2 | a | tst.js:6:3:6:9 | (b\|[b]) | +| tst.js:7:2:7:2 | a | tst.js:7:3:7:10 | ([b][c]) | +| tst.js:7:4:7:6 | [b] | tst.js:7:7:7:9 | [c] | +| tst.js:7:5:7:5 | b | tst.js:7:7:7:9 | [c] | +| tst.js:8:2:8:2 | a | tst.js:8:3:8:13 | (b\|[b]\|[b]) | +| tst.js:11:2:11:4 | (a) | tst.js:11:5:11:5 | b | +| tst.js:11:3:11:3 | a | tst.js:11:5:11:5 | b | +| tst.js:12:2:12:4 | (a) | tst.js:12:5:12:6 | bc | +| tst.js:12:3:12:3 | a | tst.js:12:5:12:6 | bc | +| tst.js:13:2:13:5 | (ab) | tst.js:13:6:13:6 | c | +| tst.js:13:3:13:4 | ab | tst.js:13:6:13:6 | c | +| tst.js:14:2:14:7 | ([a]b) | tst.js:14:8:14:8 | c | +| tst.js:14:3:14:5 | [a] | tst.js:14:6:14:6 | b | +| tst.js:14:3:14:5 | [a] | tst.js:14:8:14:8 | c | +| tst.js:14:3:14:6 | [a]b | tst.js:14:8:14:8 | c | +| tst.js:14:4:14:4 | a | tst.js:14:6:14:6 | b | +| tst.js:14:4:14:4 | a | tst.js:14:8:14:8 | c | +| tst.js:14:6:14:6 | b | tst.js:14:8:14:8 | c | +| tst.js:16:2:16:9 | ([a][b]) | tst.js:16:10:16:10 | c | +| tst.js:16:3:16:5 | [a] | tst.js:16:6:16:8 | [b] | +| tst.js:16:3:16:5 | [a] | tst.js:16:10:16:10 | c | +| tst.js:16:3:16:8 | [a][b] | tst.js:16:10:16:10 | c | +| tst.js:16:4:16:4 | a | tst.js:16:6:16:8 | [b] | +| tst.js:16:4:16:4 | a | tst.js:16:10:16:10 | c | +| tst.js:16:6:16:8 | [b] | tst.js:16:10:16:10 | c | +| tst.js:16:7:16:7 | b | tst.js:16:10:16:10 | c | +| tst.js:17:2:17:12 | ([a]\|[a]\|a) | tst.js:17:13:17:13 | b | +| tst.js:17:3:17:5 | [a] | tst.js:17:13:17:13 | b | +| tst.js:17:3:17:11 | [a]\|[a]\|a | tst.js:17:13:17:13 | b | +| tst.js:17:4:17:4 | a | tst.js:17:13:17:13 | b | +| tst.js:17:7:17:9 | [a] | tst.js:17:13:17:13 | b | +| tst.js:17:8:17:8 | a | tst.js:17:13:17:13 | b | +| tst.js:17:11:17:11 | a | tst.js:17:13:17:13 | b | diff --git a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.ql b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.ql new file mode 100644 index 00000000000..49916f8c426 --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.ql @@ -0,0 +1,5 @@ +import javascript + +from RegExpTerm pred, RegExpTerm succ +where succ = pred.getSuccessor() +select pred, succ \ No newline at end of file diff --git a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/tst.js b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/tst.js new file mode 100644 index 00000000000..25924a257d3 --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/tst.js @@ -0,0 +1,17 @@ +/ab/; +/a(b)/; +/ab(c)/; +/a(bc)/; +/a(b[c])/; +/a(b|[b])/; +/a([b][c])/; +/a(b|[b]|[b])/; + +/ab/; +/(a)b/; +/(a)bc/; +/(ab)c/; +/([a]b)c/; +/([a]|a)|b/; +/([a][b])c/; +/([a]|[a]|a)b/; From 53756041096f083533473da8ed7368ee589852c8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Feb 2020 13:15:46 +0100 Subject: [PATCH 032/134] calling `pop` or `shift` on a SplitPath returns a PosixPath --- .../security/dataflow/TaintedPath.qll | 7 +++- .../CWE-022/TaintedPath/TaintedPath.expected | 38 +++++++++++++++++++ .../CWE-022/TaintedPath/TaintedPath.js | 4 +- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index 4ff45dfc4cf..8af939e56f3 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -114,7 +114,12 @@ module TaintedPath { or ( name = "pop" or - name = "shift" or + name = "shift" + ) and + srclabel instanceof Label::SplitPath and + dstlabel.(Label::PosixPath).canContainDotDotSlash() + or + ( name = "slice" or name = "splice" or name = "concat" diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 46d124eaeae..eb528950574 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1106,6 +1106,23 @@ nodes | TaintedPath.js:143:19:143:38 | concatted2.join("/") | | TaintedPath.js:143:19:143:38 | concatted2.join("/") | | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:145:19:145:23 | split | +| TaintedPath.js:145:19:145:23 | split | +| TaintedPath.js:145:19:145:23 | split | +| TaintedPath.js:145:19:145:23 | split | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:29 | split.pop() | | normalizedPaths.js:11:7:11:27 | path | | normalizedPaths.js:11:7:11:27 | path | | normalizedPaths.js:11:7:11:27 | path | @@ -3615,6 +3632,10 @@ edges | TaintedPath.js:130:7:130:29 | split | TaintedPath.js:142:20:142:24 | split | | TaintedPath.js:130:7:130:29 | split | TaintedPath.js:142:20:142:24 | split | | TaintedPath.js:130:7:130:29 | split | TaintedPath.js:142:20:142:24 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:145:19:145:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:145:19:145:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:145:19:145:23 | split | +| TaintedPath.js:130:7:130:29 | split | TaintedPath.js:145:19:145:23 | split | | TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | | TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | | TaintedPath.js:130:15:130:18 | path | TaintedPath.js:130:15:130:29 | path.split("/") | @@ -3755,6 +3776,22 @@ edges | TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | | TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | | TaintedPath.js:143:19:143:28 | concatted2 | TaintedPath.js:143:19:143:38 | concatted2.join("/") | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | +| TaintedPath.js:145:19:145:23 | split | TaintedPath.js:145:19:145:29 | split.pop() | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | @@ -5017,6 +5054,7 @@ edges | TaintedPath.js:137:19:137:35 | prefix + split[x] | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:137:19:137:35 | prefix + split[x] | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | | TaintedPath.js:140:19:140:37 | concatted.join("/") | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:140:19:140:37 | concatted.join("/") | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | | TaintedPath.js:143:19:143:38 | concatted2.join("/") | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:143:19:143:38 | concatted2.join("/") | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | +| TaintedPath.js:145:19:145:29 | split.pop() | TaintedPath.js:126:24:126:30 | req.url | TaintedPath.js:145:19:145:29 | split.pop() | This path depends on $@. | TaintedPath.js:126:24:126:30 | req.url | a user-provided value | | normalizedPaths.js:13:19:13:22 | path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:13:19:13:22 | path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | | normalizedPaths.js:14:19:14:29 | './' + path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:14:19:14:29 | './' + path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | | normalizedPaths.js:15:19:15:38 | path + '/index.html' | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:15:19:15:38 | path + '/index.html' | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js index 4044e16a34d..3d1d6297a76 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js @@ -140,6 +140,8 @@ var server = http.createServer(function(req, res) { fs.readFileSync(concatted.join("/")); // NOT OK var concatted2 = split.concat(prefix); - fs.readFileSync(concatted2.join("/")); // NOT OK + fs.readFileSync(concatted2.join("/")); // NOT OK + + fs.readFileSync(split.pop()); // NOT OK }); \ No newline at end of file From b07f3d36d8b92498f7be7fd8159bd89a9974032a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Feb 2020 13:17:12 +0100 Subject: [PATCH 033/134] qldoc on splitPath --- .../javascript/security/dataflow/TaintedPathCustomizations.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index cbb62d7b95d..acf989a133e 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -109,6 +109,9 @@ module TaintedPath { } } + /** + * A flow label representing an array of path elements that may include "..". + */ class SplitPath extends DataFlow::FlowLabel { SplitPath() { this = "splitPath" From 8a9587fc9178fba04930cc0c8d7b39172ae6567c Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 17 Feb 2020 13:00:53 +0100 Subject: [PATCH 034/134] JS: fix RegExp::getSuccessor/getPredecessor for sequence end/starts --- .../ql/src/semmle/javascript/Regexp.qll | 45 ++++++++++++------- .../getPredecessor.expected | 4 -- .../getSuccessor.expected | 4 -- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Regexp.qll b/javascript/ql/src/semmle/javascript/Regexp.qll index 29e5a1bae3e..c8118b20a62 100644 --- a/javascript/ql/src/semmle/javascript/Regexp.qll +++ b/javascript/ql/src/semmle/javascript/Regexp.qll @@ -75,26 +75,41 @@ class RegExpTerm extends Locatable, @regexpterm { /** Gets the regular expression term that is matched (textually) before this one, if any. */ RegExpTerm getPredecessor() { - exists(RegExpSequence seq, int i | - seq.getChild(i) = this and - seq.getChild(i - 1) = result + exists(RegExpTerm parent | parent = getParent() | + if parent instanceof RegExpSequence + then + exists(RegExpSequence seq, int i | + seq = parent and + seq.getChild(i) = this + | + seq.getChild(i - 1) = result + or + i = 0 and result = seq.getPredecessor() + ) + else ( + not parent instanceof RegExpSubPattern and + result = parent.getPredecessor() + ) ) - or - result = getParent().(RegExpTerm).getPredecessor() } /** Gets the regular expression term that is matched (textually) after this one, if any. */ RegExpTerm getSuccessor() { - exists(RegExpSequence seq, int i | - seq.getChild(i) = this and - seq.getChild(i + 1) = result - ) - or - exists(RegExpTerm parent | - parent = getParent() and - not parent instanceof RegExpSubPattern - | - result = parent.getSuccessor() + exists(RegExpTerm parent | parent = getParent() | + if parent instanceof RegExpSequence + then + exists(RegExpSequence seq, int i | + seq = parent and + seq.getChild(i) = this + | + seq.getChild(i + 1) = result + or + i = seq.getNumChild() - 1 and result = seq.getSuccessor() + ) + else ( + not parent instanceof RegExpSubPattern and + result = parent.getSuccessor() + ) ) } diff --git a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected index 4758562cf3c..d2414fd2500 100644 --- a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected +++ b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getPredecessor.expected @@ -7,8 +7,6 @@ | tst.js:5:2:5:2 | a | tst.js:5:3:5:8 | (b[c]) | | tst.js:5:2:5:2 | a | tst.js:5:4:5:4 | b | | tst.js:5:2:5:2 | a | tst.js:5:4:5:7 | b[c] | -| tst.js:5:2:5:2 | a | tst.js:5:5:5:7 | [c] | -| tst.js:5:2:5:2 | a | tst.js:5:6:5:6 | c | | tst.js:5:4:5:4 | b | tst.js:5:5:5:7 | [c] | | tst.js:5:4:5:4 | b | tst.js:5:6:5:6 | c | | tst.js:6:2:6:2 | a | tst.js:6:3:6:9 | (b\|[b]) | @@ -20,8 +18,6 @@ | tst.js:7:2:7:2 | a | tst.js:7:4:7:6 | [b] | | tst.js:7:2:7:2 | a | tst.js:7:4:7:9 | [b][c] | | tst.js:7:2:7:2 | a | tst.js:7:5:7:5 | b | -| tst.js:7:2:7:2 | a | tst.js:7:7:7:9 | [c] | -| tst.js:7:2:7:2 | a | tst.js:7:8:7:8 | c | | tst.js:7:4:7:6 | [b] | tst.js:7:7:7:9 | [c] | | tst.js:7:4:7:6 | [b] | tst.js:7:8:7:8 | c | | tst.js:8:2:8:2 | a | tst.js:8:3:8:13 | (b\|[b]\|[b]) | diff --git a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected index 60ba52bb03c..e8550156fb3 100644 --- a/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected +++ b/javascript/ql/test/library-tests/RegExp/predecessors_and_successors/getSuccessor.expected @@ -16,17 +16,13 @@ | tst.js:13:3:13:4 | ab | tst.js:13:6:13:6 | c | | tst.js:14:2:14:7 | ([a]b) | tst.js:14:8:14:8 | c | | tst.js:14:3:14:5 | [a] | tst.js:14:6:14:6 | b | -| tst.js:14:3:14:5 | [a] | tst.js:14:8:14:8 | c | | tst.js:14:3:14:6 | [a]b | tst.js:14:8:14:8 | c | | tst.js:14:4:14:4 | a | tst.js:14:6:14:6 | b | -| tst.js:14:4:14:4 | a | tst.js:14:8:14:8 | c | | tst.js:14:6:14:6 | b | tst.js:14:8:14:8 | c | | tst.js:16:2:16:9 | ([a][b]) | tst.js:16:10:16:10 | c | | tst.js:16:3:16:5 | [a] | tst.js:16:6:16:8 | [b] | -| tst.js:16:3:16:5 | [a] | tst.js:16:10:16:10 | c | | tst.js:16:3:16:8 | [a][b] | tst.js:16:10:16:10 | c | | tst.js:16:4:16:4 | a | tst.js:16:6:16:8 | [b] | -| tst.js:16:4:16:4 | a | tst.js:16:10:16:10 | c | | tst.js:16:6:16:8 | [b] | tst.js:16:10:16:10 | c | | tst.js:16:7:16:7 | b | tst.js:16:10:16:10 | c | | tst.js:17:2:17:12 | ([a]\|[a]\|a) | tst.js:17:13:17:13 | b | From 9249b92d85fcc83512a064cc1ef4a42542f57f0f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 17 Feb 2020 12:48:13 +0000 Subject: [PATCH 035/134] JS: Fix typo in comment --- javascript/ql/src/semmle/javascript/dataflow/Nodes.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index ffb88afadf5..7144785792e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -1247,7 +1247,7 @@ module PartialInvokeNode { DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) { none() } /** - * DEPRECATED. Use the two-argument version of `getBoundReceiver` instead. + * DEPRECATED. Use the one-argument version of `getBoundReceiver` instead. * * Gets the node holding the receiver to be passed to the bound function, if specified. */ From 2885d48ad01cee677019f0f3e616f30ba237bc34 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Feb 2020 14:44:10 +0100 Subject: [PATCH 036/134] changes based on review --- .../security/dataflow/TaintedPath.qll | 2 +- .../dataflow/TaintedPathCustomizations.qll | 31 +++++++-------- .../CWE-022/TaintedPath/TaintedPath.expected | 38 +++++++++++++++++++ .../CWE-022/TaintedPath/normalizedPaths.js | 8 ++++ 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index c72257b47c0..e57d3ccb3aa 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -36,7 +36,7 @@ module TaintedPath { guard instanceof StartsWithDirSanitizer or guard instanceof IsAbsoluteSanitizer or guard instanceof ContainsDotDotSanitizer or - guard instanceof RelativePathContainsDotDotGuard + guard instanceof RelativePathStartsWithDotDotSanitizer } override predicate isAdditionalFlowStep( diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index fc8ac5b1a84..a27080da74d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -353,20 +353,22 @@ module TaintedPath { /** * A sanitizer that recognizes the following pattern: - * var relative = path.relative(webroot, pathname); - * if(relative.startsWith(".." + path.sep) || relative == "..") { - * // pathname is unsafe - * } else { - * // pathname is safe - * } + * ``` + * var relative = path.relative(webroot, pathname); + * if(relative.startsWith(".." + path.sep) || relative == "..") { + * // pathname is unsafe + * } else { + * // pathname is safe + * } + * ``` */ - class RelativePathContainsDotDotGuard extends DataFlow::BarrierGuardNode { + class RelativePathStartsWithDotDotSanitizer extends DataFlow::BarrierGuardNode { StringOps::StartsWith startsWith; DataFlow::CallNode relativeCall; - RelativePathContainsDotDotGuard() { + RelativePathStartsWithDotDotSanitizer() { this = startsWith and - relativeCall = DataFlow::moduleImport("path").getAMemberCall("relative") and + relativeCall = NodeJSLib::Path::moduleMember("relative").getACall() and ( startsWith.getBaseString().getALocalSource() = relativeCall or @@ -377,18 +379,11 @@ module TaintedPath { .getInput() .getALocalSource() = relativeCall ) and - exists(DataFlow::Node subString, string prefix | - subString = startsWith.getSubstring() and - (prefix = ".." or prefix = "../") - | - subString.mayHaveStringValue(prefix) - or - subString.(StringOps::ConcatenationRoot).getFirstLeaf().mayHaveStringValue(prefix) - ) + isDotDotSlashPrefix(startsWith.getSubstring()) } override predicate blocks(boolean outcome, Expr e) { - e = relativeCall.getArgument(1).asExpr() and outcome = false + e = relativeCall.getArgument(1).asExpr() and outcome = startsWith.getPolarity().booleanNot() } } diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index ab0869ca257..81bc0310f5e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1333,6 +1333,23 @@ nodes | normalizedPaths.js:286:21:286:27 | newpath | | normalizedPaths.js:286:21:286:27 | newpath | | normalizedPaths.js:286:21:286:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | +| normalizedPaths.js:291:38:291:41 | path | +| normalizedPaths.js:291:38:291:41 | path | +| normalizedPaths.js:291:38:291:41 | path | +| normalizedPaths.js:291:38:291:41 | path | +| normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:296:21:296:27 | newpath | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -3732,6 +3749,10 @@ edges | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:283:38:283:41 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:283:38:283:41 | path | | normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:283:38:283:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:291:38:291:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:291:38:291:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:291:38:291:41 | path | +| normalizedPaths.js:254:7:254:47 | path | normalizedPaths.js:291:38:291:41 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | | normalizedPaths.js:254:14:254:47 | pathMod ... y.path) | normalizedPaths.js:254:7:254:47 | path | @@ -3792,6 +3813,22 @@ edges | normalizedPaths.js:283:38:283:41 | path | normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | | normalizedPaths.js:283:38:283:41 | path | normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | | normalizedPaths.js:283:38:283:41 | path | normalizedPaths.js:283:17:283:42 | pathMod ... e(path) | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:7:291:42 | newpath | normalizedPaths.js:296:21:296:27 | newpath | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | normalizedPaths.js:291:7:291:42 | newpath | +| normalizedPaths.js:291:38:291:41 | path | normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | +| normalizedPaths.js:291:38:291:41 | path | normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | +| normalizedPaths.js:291:38:291:41 | path | normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | +| normalizedPaths.js:291:38:291:41 | path | normalizedPaths.js:291:17:291:42 | pathMod ... e(path) | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -4578,6 +4615,7 @@ edges | normalizedPaths.js:270:21:270:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:270:21:270:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | normalizedPaths.js:278:21:278:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:278:21:278:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | normalizedPaths.js:286:21:286:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:286:21:286:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | +| normalizedPaths.js:296:21:296:27 | newpath | normalizedPaths.js:254:33:254:46 | req.query.path | normalizedPaths.js:296:21:296:27 | newpath | This path depends on $@. | normalizedPaths.js:254:33:254:46 | req.query.path | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js index c718d9075c6..98f71a7f0f3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js @@ -287,4 +287,12 @@ app.get('/relative-startswith', (req, res) => { } else { fs.readFileSync(newpath); // OK! } + + let newpath = pathModule.normalize(path); + var relativePath = pathModule.relative(pathModule.normalize(workspaceDir), newpath); + if (pathModule.normalize(relativePath).indexOf('../')) { + fs.readFileSync(newpath); // OK! + } else { + fs.readFileSync(newpath); // NOT OK! + } }); From 56e5bd50f61f392d5e4fb58477d875b6669f4f61 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Feb 2020 14:55:08 +0100 Subject: [PATCH 037/134] update expected output --- .../Security/CWE-022/TaintedPath/Consistency.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected index 396d9811ad8..68ed692f741 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected @@ -1,3 +1,4 @@ | normalizedPaths.js:208:38:208:63 | // OK - ... anyway | Spurious alert | | tainted-string-steps.js:25:43:25:74 | // NOT ... flagged | Missing alert | | tainted-string-steps.js:26:49:26:74 | // OK - ... flagged | Spurious alert | +| tainted-string-steps.js:28:39:28:70 | // NOT ... flagged | Missing alert | From 3a4f52315cceba07b0a43256819e8fe463455622 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 12 Feb 2020 16:34:35 +0100 Subject: [PATCH 038/134] Data flow: Track simple call contexts in `nodeCand[Fwd]1` --- .../csharp/dataflow/internal/DataFlowImpl.qll | 243 ++++++++++++------ 1 file changed, 169 insertions(+), 74 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..cce49032808 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) From a695b567ece1b518d27c1f0cd6085c4154922816 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 17 Feb 2020 19:39:52 +0100 Subject: [PATCH 039/134] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 243 ++++++++++++------ .../cpp/dataflow/internal/DataFlowImpl2.qll | 243 ++++++++++++------ .../cpp/dataflow/internal/DataFlowImpl3.qll | 243 ++++++++++++------ .../cpp/dataflow/internal/DataFlowImpl4.qll | 243 ++++++++++++------ .../dataflow/internal/DataFlowImplLocal.qll | 243 ++++++++++++------ .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 243 ++++++++++++------ .../ir/dataflow/internal/DataFlowImpl2.qll | 243 ++++++++++++------ .../ir/dataflow/internal/DataFlowImpl3.qll | 243 ++++++++++++------ .../ir/dataflow/internal/DataFlowImpl4.qll | 243 ++++++++++++------ .../dataflow/internal/DataFlowImpl2.qll | 243 ++++++++++++------ .../dataflow/internal/DataFlowImpl3.qll | 243 ++++++++++++------ .../dataflow/internal/DataFlowImpl4.qll | 243 ++++++++++++------ .../dataflow/internal/DataFlowImpl5.qll | 243 ++++++++++++------ .../java/dataflow/internal/DataFlowImpl.qll | 243 ++++++++++++------ .../java/dataflow/internal/DataFlowImpl2.qll | 243 ++++++++++++------ .../java/dataflow/internal/DataFlowImpl3.qll | 243 ++++++++++++------ .../java/dataflow/internal/DataFlowImpl4.qll | 243 ++++++++++++------ .../java/dataflow/internal/DataFlowImpl5.qll | 243 ++++++++++++------ 18 files changed, 3042 insertions(+), 1332 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..cce49032808 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..cce49032808 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..cce49032808 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..cce49032808 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 86d44e4fcce..cce49032808 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..cce49032808 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..cce49032808 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..cce49032808 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..cce49032808 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 86d44e4fcce..cce49032808 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { /** * Holds if `node` is reachable from a source in the given configuration - * ignoring call contexts. + * taking simple call contexts into consideration. */ -private predicate nodeCandFwd1(Node node, Configuration config) { +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and ( - config.isSource(node) + config.isSource(node) and + fromArg = false or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and localFlowStep(mid, node, config) ) or exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and additionalLocalFlowStep(mid, node, config) ) or exists(Node mid | nodeCandFwd1(mid, config) and - jumpStep(mid, node, config) + jumpStep(mid, node, config) and + fromArg = false ) or exists(Node mid | nodeCandFwd1(mid, config) and - additionalJumpStep(mid, node, config) + additionalJumpStep(mid, node, config) and + fromArg = false ) or // store exists(Node mid | useFieldFlow(config) and - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and storeDirect(mid, _, node) and not outBarrier(mid, config) ) or // read exists(Content f | - nodeCandFwd1Read(f, node, config) and + nodeCandFwd1Read(f, node, fromArg, config) and storeCandFwd1(f, config) and not inBarrier(node, config) ) @@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) { // flow into a callable exists(Node arg | nodeCandFwd1(arg, config) and - viableParamArg(_, node, arg) + viableParamArg(_, node, arg) and + fromArg = true ) or // flow out of a callable - exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | - nodeCandFwd1ReturnPosition(pos, config) and - pos = viableReturnPos(call, kind) and - node = kind.getAnOutNode(call) + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + flowOutCandFwd1(call, fromArg, config) ) ) } -pragma[noinline] -private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) { +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { exists(ReturnNodeExt ret | - nodeCandFwd1(ret, config) and + nodeCandFwd1(ret, fromArg, config) and getReturnPosition(ret) = pos ) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { exists(Node mid | - nodeCandFwd1(mid, config) and + nodeCandFwd1(mid, fromArg, config) and readDirect(mid, f, node) ) } @@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) { /** * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. */ -pragma[noinline] +pragma[nomagic] private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | not fullBarrier(node, config) and @@ -345,68 +355,117 @@ private predicate storeCandFwd1(Content f, Configuration config) { ) } +pragma[nomagic] +private predicate nodeCandFwd1ReturnKind( + DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config +) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + pos = viableReturnPos(call, kind) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out( + DataFlowCall call, Node node, boolean fromArg, Configuration config +) { + exists(ReturnKindExt kind | + nodeCandFwd1ReturnKind(call, kind, fromArg, config) and + node = kind.getAnOutNode(call) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** * Holds if `node` is part of a path from a source to a sink in the given - * configuration ignoring call contexts. + * configuration taking simple call contexts into consideration. */ pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { nodeCandFwd1(node, config) and - config.isSink(node) + config.isSink(node) and + toReturn = false or - nodeCandFwd1(node, unbind(config)) and - ( - exists(Node mid | - localFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + readCand1(f, config) + ) + or + // read + exists(Node mid, Content f | + readDirect(node, f, mid) and + storeCandFwd1(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1ParamArg(call, node, false, config) and + toReturn = false or - exists(Node mid | - additionalLocalFlowStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - jumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - exists(Node mid | - additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) - ) - or - // store - exists(Content f | - nodeCand1Store(f, node, config) and - readCand1(f, config) - ) - or - // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) - ) - or - // flow into a callable - exists(Node param | - viableParamArg(_, param, node) and - nodeCand1(param, config) - ) - or - // flow out of a callable - exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and - getReturnPosition(node) = pos - ) + nodeCand1ParamArgToReturn(call, node, config) and + flowInCand1(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1ReturnPosition(pos, config) and + getReturnPosition(node) = pos and + toReturn = true ) } -pragma[noinline] +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | nodeCand1(out, config) and @@ -418,7 +477,7 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf /** * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. */ -pragma[noinline] +pragma[nomagic] private predicate readCand1(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and @@ -430,9 +489,9 @@ private predicate readCand1(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, Configuration config) { +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | - nodeCand1(mid, config) and + nodeCand1(mid, toReturn, config) and storeCandFwd1(f, unbind(config)) and storeDirect(node, f, mid) ) @@ -444,11 +503,47 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) { */ private predicate readStoreCand1(Content f, Configuration conf) { readCand1(f, conf) and - nodeCand1Store(f, _, conf) + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableParamArgCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1ParamArg( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1ParamArgToReturn( + DataFlowCall call, ArgumentNode arg, Configuration config +) { + nodeCand1ParamArg(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) } private predicate throughFlowNodeCand(Node node, Configuration config) { - nodeCand1(node, config) and + nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and not outBarrier(node, config) From c5986c52d3cd25082aa87e29c1931cc5557733ed Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Mon, 17 Feb 2020 11:28:39 -0800 Subject: [PATCH 040/134] Renames typeErrorType to typeError --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 4735001dd68..1c4c5014ceb 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -745,7 +745,7 @@ module ClassValue { } /** Get the `ClassValue` for the `TypeError` class */ - ClassValue typeErrorType() { + ClassValue typeError() { result = TBuiltinClassObject(Builtin::special("TypeError")) } From c36c0aeb8854f64ddc1fd1c53cd5ed52502e15ab Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Mon, 17 Feb 2020 12:09:01 -0800 Subject: [PATCH 041/134] Fixes renaming bug --- python/ql/src/Expressions/HashedButNoHash.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Expressions/HashedButNoHash.ql b/python/ql/src/Expressions/HashedButNoHash.ql index a28180d799c..37da9407b7f 100644 --- a/python/ql/src/Expressions/HashedButNoHash.ql +++ b/python/ql/src/Expressions/HashedButNoHash.ql @@ -69,7 +69,7 @@ predicate is_unhashable(ControlFlowNode f, ClassValue cls, ControlFlowNode origi predicate typeerror_is_caught(ControlFlowNode f) { exists (Try try | try.getBody().contains(f.getNode()) and - try.getAHandler().getType().pointsTo(ClassValue::typeErrorType())) + try.getAHandler().getType().pointsTo(ClassValue::typeError())) } from ControlFlowNode f, ClassValue c, ControlFlowNode origin From e8938fb4667ae2730e71aa82da17209464c7bfac Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 17 Feb 2020 23:20:25 +0100 Subject: [PATCH 042/134] JS: introduce RegExpSequence::nextElement and previousElement --- .../ql/src/semmle/javascript/Regexp.qll | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Regexp.qll b/javascript/ql/src/semmle/javascript/Regexp.qll index c8118b20a62..d0b39ce59b6 100644 --- a/javascript/ql/src/semmle/javascript/Regexp.qll +++ b/javascript/ql/src/semmle/javascript/Regexp.qll @@ -76,40 +76,22 @@ class RegExpTerm extends Locatable, @regexpterm { /** Gets the regular expression term that is matched (textually) before this one, if any. */ RegExpTerm getPredecessor() { exists(RegExpTerm parent | parent = getParent() | - if parent instanceof RegExpSequence - then - exists(RegExpSequence seq, int i | - seq = parent and - seq.getChild(i) = this - | - seq.getChild(i - 1) = result - or - i = 0 and result = seq.getPredecessor() - ) - else ( - not parent instanceof RegExpSubPattern and - result = parent.getPredecessor() - ) + result = parent.(RegExpSequence).previousElement(this) + or + not exists(parent.(RegExpSequence).previousElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getPredecessor() ) } /** Gets the regular expression term that is matched (textually) after this one, if any. */ RegExpTerm getSuccessor() { exists(RegExpTerm parent | parent = getParent() | - if parent instanceof RegExpSequence - then - exists(RegExpSequence seq, int i | - seq = parent and - seq.getChild(i) = this - | - seq.getChild(i + 1) = result - or - i = seq.getNumChild() - 1 and result = seq.getSuccessor() - ) - else ( - not parent instanceof RegExpSubPattern and - result = parent.getSuccessor() - ) + result = parent.(RegExpSequence).nextElement(this) + or + not exists(parent.(RegExpSequence).nextElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getSuccessor() ) } @@ -328,6 +310,19 @@ class RegExpSequence extends RegExpTerm, @regexp_seq { or result = getChild(i).getConstantValue() + getConstantValue(i+1) } + + /** Gets the element preceding `element` in this sequence. */ + RegExpTerm previousElement(RegExpTerm element) { + element = nextElement(result) + } + + /** Gets the element following `element` in this sequence. */ + RegExpTerm nextElement(RegExpTerm element) { + exists(int i | + element = this.getChild(i) and + result = this.getChild(i + 1) + ) + } } /** From 0d239e8bd2369cee4081c045dec2331e8052219a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 17 Feb 2020 15:26:11 +0100 Subject: [PATCH 043/134] C++: Manual magic for `isInCycle` The `isInCycle` predicate would take a long time on Wireshark with 6GB RAM, sometimes OOMing in the fastTC HOP. Analyzing wireshark with 6GB is important because that's the standard configuration on our Jenkins workers. With this commit, I can analyze Wireshark with 6GB on my laptop. The `getNonPhiOperandDef` predicate on Wireshark is 34M tuples, while `getDefIfHasNeighbors` is 11M tuples, and the TC of `getDefIfHasNeighbors` is 23M tuples (487 MB). --- .../raw/internal/IRConstruction.qll | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 849dbce0343..96ae480405a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -102,6 +102,19 @@ private module Cached { result = getMemoryOperandDefinition(instr, _, _) } + /** + * Gets a non-phi instruction that defines an operand of `instr` but only if + * both `instr` and the result have neighbor on the other side of the edge + * between them. This is a necessary condition for being in a cycle, and it + * removes about two thirds of the tuples that would otherwise be in this + * predicate. + */ + private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) { + result = getNonPhiOperandDef(instr) and + exists(getNonPhiOperandDef(result)) and + instr = getNonPhiOperandDef(_) + } + /** * Holds if `instr` is part of a cycle in the operand graph that doesn't go * through a phi instruction and therefore should be impossible. @@ -115,7 +128,7 @@ private module Cached { cached predicate isInCycle(Instruction instr) { instr instanceof Instruction and - getNonPhiOperandDef+(instr) = instr + getNonPhiOperandDefOfIntermediate+(instr) = instr } cached From e359e1a373d4906aebe6198c3cc9ea80b5cb70a4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 18 Feb 2020 10:57:28 +0100 Subject: [PATCH 044/134] use a barrier directly instead of a barrier guard --- .../CWE-400/PrototypePollutionUtility.ql | 9 +- .../javascript/dataflow/Configuration.qll | 19 +- .../javascript/dataflow/TaintTracking.qll | 18 +- .../security/dataflow/TaintedPath.qll | 3 +- .../dataflow/TaintedPathCustomizations.qll | 5 + .../TaintBarriers/SanitizingGuard.expected | 351 ------------------ 6 files changed, 24 insertions(+), 381 deletions(-) diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index b882165ffaa..317aa6fcc22 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -185,6 +185,12 @@ class PropNameTracking extends DataFlow::Configuration { ) } + override predicate isBarrier(DataFlow::Node node) { + super.isBarrier(node) + or + node instanceof DataFlow::VarAccessBarrier + } + override predicate isBarrierGuard(DataFlow::BarrierGuardNode node) { node instanceof BlacklistEqualityGuard or node instanceof WhitelistEqualityGuard or @@ -193,8 +199,7 @@ class PropNameTracking extends DataFlow::Configuration { node instanceof InstanceOfGuard or node instanceof TypeofGuard or node instanceof BlacklistInclusionGuard or - node instanceof WhitelistInclusionGuard or - node instanceof DataFlow::VarAccessBarrierGuard + node instanceof WhitelistInclusionGuard } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 873a1dbed6a..0cba3157ba9 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1483,16 +1483,15 @@ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, Dat /** * A check of the form `if(x)`, which sanitizes `x` in its "else" branch. - * Can be added to a `isBarrierGuard` in a configuration to add the sanitization. + * Can be added to a `isBarrier` in a configuration to add the sanitization. */ -class VarAccessBarrierGuard extends BarrierGuardNode, DataFlow::Node { - VarAccess var; - - VarAccessBarrierGuard() { - var = this.getEnclosingExpr() - } - - override predicate blocks(boolean outcome, Expr e) { - var = e and outcome = false +class VarAccessBarrier extends DataFlow::Node { + VarAccessBarrier() { + exists(ConditionGuardNode guard, SsaRefinementNode refinement | + this = DataFlow::ssaDefinitionNode(refinement) and + refinement.getGuard() = guard and + guard.getTest() instanceof VarAccess and + guard.getOutcome() = false + ) } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index fa573cf908a..ba14bf65f66 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -89,7 +89,8 @@ module TaintTracking { final override predicate isBarrier(DataFlow::Node node) { super.isBarrier(node) or - isSanitizer(node) + isSanitizer(node) or + node instanceof DataFlow::VarAccessBarrier } final override predicate isBarrierEdge(DataFlow::Node source, DataFlow::Node sink) { @@ -914,19 +915,4 @@ module TaintTracking { DataFlow::localFlowStep(pred, succ) or any(AdditionalTaintStep s).step(pred, succ) } - - /** A check of the form `if(x)`, which sanitizes `x` in its "else" branch. */ - private class VarAccessBarrierGuard extends AdditionalSanitizerGuardNode, DataFlow::Node { - DataFlow::VarAccessBarrierGuard guard; - - VarAccessBarrierGuard() { - this = guard - } - - override predicate sanitizes(boolean outcome, Expr e) { - guard.blocks(outcome, e) - } - - override predicate appliesTo(Configuration cfg) { any() } - } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index 5e888b6e768..b46f7d508f7 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -35,8 +35,7 @@ module TaintedPath { guard instanceof StartsWithDotDotSanitizer or guard instanceof StartsWithDirSanitizer or guard instanceof IsAbsoluteSanitizer or - guard instanceof ContainsDotDotSanitizer or - guard instanceof DataFlow::VarAccessBarrierGuard + guard instanceof ContainsDotDotSanitizer } override predicate isAdditionalFlowStep( diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 25bb232f8fe..62e42b1963a 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -355,6 +355,11 @@ module TaintedPath { } } + /** + * A check of the form `if(x)`, which sanitizes `x` in its "else" branch. + */ + class VarAccessBarrier extends Sanitizer, DataFlow::VarAccessBarrier { } + /** * A source of remote user input, considered as a flow source for * tainted-path vulnerabilities. diff --git a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected index d09005ef78b..cf568e8c593 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected @@ -1,419 +1,68 @@ -| tst.js:2:13:2:18 | SOURCE | ExampleConfiguration | false | tst.js:2:13:2:18 | SOURCE | -| tst.js:3:5:3:8 | SINK | ExampleConfiguration | false | tst.js:3:5:3:8 | SINK | -| tst.js:3:10:3:10 | v | ExampleConfiguration | false | tst.js:3:10:3:10 | v | | tst.js:5:9:5:21 | /^x$/.test(v) | ExampleConfiguration | true | tst.js:5:20:5:20 | v | -| tst.js:5:20:5:20 | v | ExampleConfiguration | false | tst.js:5:20:5:20 | v | -| tst.js:6:9:6:12 | SINK | ExampleConfiguration | false | tst.js:6:9:6:12 | SINK | -| tst.js:6:14:6:14 | v | ExampleConfiguration | false | tst.js:6:14:6:14 | v | -| tst.js:8:9:8:12 | SINK | ExampleConfiguration | false | tst.js:8:9:8:12 | SINK | -| tst.js:8:14:8:14 | v | ExampleConfiguration | false | tst.js:8:14:8:14 | v | -| tst.js:11:9:11:9 | v | ExampleConfiguration | false | tst.js:11:9:11:9 | v | | tst.js:11:9:11:25 | v.match(/[^a-z]/) | ExampleConfiguration | false | tst.js:11:9:11:9 | v | -| tst.js:12:9:12:12 | SINK | ExampleConfiguration | false | tst.js:12:9:12:12 | SINK | -| tst.js:12:14:12:14 | v | ExampleConfiguration | false | tst.js:12:14:12:14 | v | -| tst.js:14:9:14:12 | SINK | ExampleConfiguration | false | tst.js:14:9:14:12 | SINK | -| tst.js:14:14:14:14 | v | ExampleConfiguration | false | tst.js:14:14:14:14 | v | -| tst.js:20:13:20:18 | SOURCE | ExampleConfiguration | false | tst.js:20:13:20:18 | SOURCE | -| tst.js:21:5:21:8 | SINK | ExampleConfiguration | false | tst.js:21:5:21:8 | SINK | -| tst.js:21:10:21:10 | v | ExampleConfiguration | false | tst.js:21:10:21:10 | v | -| tst.js:23:9:23:9 | o | ExampleConfiguration | false | tst.js:23:9:23:9 | o | | tst.js:23:9:23:27 | o.hasOwnProperty(v) | ExampleConfiguration | true | tst.js:23:26:23:26 | v | -| tst.js:23:26:23:26 | v | ExampleConfiguration | false | tst.js:23:26:23:26 | v | -| tst.js:24:9:24:12 | SINK | ExampleConfiguration | false | tst.js:24:9:24:12 | SINK | -| tst.js:24:14:24:14 | v | ExampleConfiguration | false | tst.js:24:14:24:14 | v | -| tst.js:26:9:26:12 | SINK | ExampleConfiguration | false | tst.js:26:9:26:12 | SINK | -| tst.js:26:14:26:14 | v | ExampleConfiguration | false | tst.js:26:14:26:14 | v | -| tst.js:32:13:32:18 | SOURCE | ExampleConfiguration | false | tst.js:32:13:32:18 | SOURCE | -| tst.js:33:5:33:8 | SINK | ExampleConfiguration | false | tst.js:33:5:33:8 | SINK | -| tst.js:33:10:33:10 | v | ExampleConfiguration | false | tst.js:33:10:33:10 | v | -| tst.js:35:9:35:9 | v | ExampleConfiguration | false | tst.js:35:9:35:9 | v | | tst.js:35:9:35:14 | v in o | ExampleConfiguration | true | tst.js:35:9:35:9 | v | -| tst.js:35:14:35:14 | o | ExampleConfiguration | false | tst.js:35:14:35:14 | o | -| tst.js:36:9:36:12 | SINK | ExampleConfiguration | false | tst.js:36:9:36:12 | SINK | -| tst.js:36:14:36:14 | v | ExampleConfiguration | false | tst.js:36:14:36:14 | v | -| tst.js:38:9:38:12 | SINK | ExampleConfiguration | false | tst.js:38:9:38:12 | SINK | -| tst.js:38:14:38:14 | v | ExampleConfiguration | false | tst.js:38:14:38:14 | v | -| tst.js:44:13:44:18 | SOURCE | ExampleConfiguration | false | tst.js:44:13:44:18 | SOURCE | -| tst.js:45:5:45:8 | SINK | ExampleConfiguration | false | tst.js:45:5:45:8 | SINK | -| tst.js:45:10:45:10 | v | ExampleConfiguration | false | tst.js:45:10:45:10 | v | -| tst.js:47:9:47:9 | o | ExampleConfiguration | false | tst.js:47:9:47:9 | o | | tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | false | tst.js:47:11:47:11 | v | | tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:9:47:12 | o[v] | -| tst.js:47:11:47:11 | v | ExampleConfiguration | false | tst.js:47:11:47:11 | v | -| tst.js:47:17:47:25 | undefined | ExampleConfiguration | false | tst.js:47:17:47:25 | undefined | -| tst.js:48:9:48:12 | SINK | ExampleConfiguration | false | tst.js:48:9:48:12 | SINK | -| tst.js:48:14:48:14 | v | ExampleConfiguration | false | tst.js:48:14:48:14 | v | -| tst.js:50:9:50:12 | SINK | ExampleConfiguration | false | tst.js:50:9:50:12 | SINK | -| tst.js:50:14:50:14 | v | ExampleConfiguration | false | tst.js:50:14:50:14 | v | -| tst.js:53:9:53:17 | undefined | ExampleConfiguration | false | tst.js:53:9:53:17 | undefined | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | false | tst.js:53:25:53:25 | v | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:23:53:26 | o[v] | -| tst.js:53:23:53:23 | o | ExampleConfiguration | false | tst.js:53:23:53:23 | o | -| tst.js:53:25:53:25 | v | ExampleConfiguration | false | tst.js:53:25:53:25 | v | -| tst.js:54:9:54:12 | SINK | ExampleConfiguration | false | tst.js:54:9:54:12 | SINK | -| tst.js:54:14:54:14 | v | ExampleConfiguration | false | tst.js:54:14:54:14 | v | -| tst.js:56:9:56:12 | SINK | ExampleConfiguration | false | tst.js:56:9:56:12 | SINK | -| tst.js:56:14:56:14 | v | ExampleConfiguration | false | tst.js:56:14:56:14 | v | -| tst.js:59:9:59:9 | o | ExampleConfiguration | false | tst.js:59:9:59:9 | o | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:9:59:12 | o[v] | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | true | tst.js:59:11:59:11 | v | -| tst.js:59:11:59:11 | v | ExampleConfiguration | false | tst.js:59:11:59:11 | v | -| tst.js:59:18:59:26 | undefined | ExampleConfiguration | false | tst.js:59:18:59:26 | undefined | -| tst.js:60:9:60:12 | SINK | ExampleConfiguration | false | tst.js:60:9:60:12 | SINK | -| tst.js:60:14:60:14 | v | ExampleConfiguration | false | tst.js:60:14:60:14 | v | -| tst.js:62:9:62:12 | SINK | ExampleConfiguration | false | tst.js:62:9:62:12 | SINK | -| tst.js:62:14:62:14 | v | ExampleConfiguration | false | tst.js:62:14:62:14 | v | -| tst.js:68:13:68:18 | SOURCE | ExampleConfiguration | false | tst.js:68:13:68:18 | SOURCE | -| tst.js:69:5:69:8 | SINK | ExampleConfiguration | false | tst.js:69:5:69:8 | SINK | -| tst.js:69:10:69:10 | v | ExampleConfiguration | false | tst.js:69:10:69:10 | v | -| tst.js:71:9:71:9 | o | ExampleConfiguration | false | tst.js:71:9:71:9 | o | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:19:71:19 | v | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:9:71:20 | o.indexOf(v) | -| tst.js:71:19:71:19 | v | ExampleConfiguration | false | tst.js:71:19:71:19 | v | -| tst.js:72:9:72:12 | SINK | ExampleConfiguration | false | tst.js:72:9:72:12 | SINK | -| tst.js:72:14:72:14 | v | ExampleConfiguration | false | tst.js:72:14:72:14 | v | -| tst.js:74:9:74:12 | SINK | ExampleConfiguration | false | tst.js:74:9:74:12 | SINK | -| tst.js:74:14:74:14 | v | ExampleConfiguration | false | tst.js:74:14:74:14 | v | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:26:77:26 | v | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:16:77:27 | o.indexOf(v) | -| tst.js:77:16:77:16 | o | ExampleConfiguration | false | tst.js:77:16:77:16 | o | -| tst.js:77:26:77:26 | v | ExampleConfiguration | false | tst.js:77:26:77:26 | v | -| tst.js:78:9:78:12 | SINK | ExampleConfiguration | false | tst.js:78:9:78:12 | SINK | -| tst.js:78:14:78:14 | v | ExampleConfiguration | false | tst.js:78:14:78:14 | v | -| tst.js:80:9:80:12 | SINK | ExampleConfiguration | false | tst.js:80:9:80:12 | SINK | -| tst.js:80:14:80:14 | v | ExampleConfiguration | false | tst.js:80:14:80:14 | v | -| tst.js:83:9:83:9 | o | ExampleConfiguration | false | tst.js:83:9:83:9 | o | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:9:83:20 | o.indexOf(v) | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:19:83:19 | v | -| tst.js:83:19:83:19 | v | ExampleConfiguration | false | tst.js:83:19:83:19 | v | -| tst.js:84:9:84:12 | SINK | ExampleConfiguration | false | tst.js:84:9:84:12 | SINK | -| tst.js:84:14:84:14 | v | ExampleConfiguration | false | tst.js:84:14:84:14 | v | -| tst.js:86:9:86:12 | SINK | ExampleConfiguration | false | tst.js:86:9:86:12 | SINK | -| tst.js:86:14:86:14 | v | ExampleConfiguration | false | tst.js:86:14:86:14 | v | -| tst.js:92:13:92:18 | SOURCE | ExampleConfiguration | false | tst.js:92:13:92:18 | SOURCE | -| tst.js:93:5:93:8 | SINK | ExampleConfiguration | false | tst.js:93:5:93:8 | SINK | -| tst.js:93:10:93:10 | v | ExampleConfiguration | false | tst.js:93:10:93:10 | v | -| tst.js:95:9:95:9 | o | ExampleConfiguration | false | tst.js:95:9:95:9 | o | | tst.js:95:9:95:21 | o.contains(v) | ExampleConfiguration | true | tst.js:95:20:95:20 | v | -| tst.js:95:20:95:20 | v | ExampleConfiguration | false | tst.js:95:20:95:20 | v | -| tst.js:96:9:96:12 | SINK | ExampleConfiguration | false | tst.js:96:9:96:12 | SINK | -| tst.js:96:14:96:14 | v | ExampleConfiguration | false | tst.js:96:14:96:14 | v | -| tst.js:98:9:98:12 | SINK | ExampleConfiguration | false | tst.js:98:9:98:12 | SINK | -| tst.js:98:14:98:14 | v | ExampleConfiguration | false | tst.js:98:14:98:14 | v | -| tst.js:104:13:104:18 | SOURCE | ExampleConfiguration | false | tst.js:104:13:104:18 | SOURCE | -| tst.js:105:5:105:8 | SINK | ExampleConfiguration | false | tst.js:105:5:105:8 | SINK | -| tst.js:105:10:105:10 | v | ExampleConfiguration | false | tst.js:105:10:105:10 | v | -| tst.js:107:9:107:9 | o | ExampleConfiguration | false | tst.js:107:9:107:9 | o | | tst.js:107:9:107:16 | o.has(v) | ExampleConfiguration | true | tst.js:107:15:107:15 | v | -| tst.js:107:15:107:15 | v | ExampleConfiguration | false | tst.js:107:15:107:15 | v | -| tst.js:108:9:108:12 | SINK | ExampleConfiguration | false | tst.js:108:9:108:12 | SINK | -| tst.js:108:14:108:14 | v | ExampleConfiguration | false | tst.js:108:14:108:14 | v | -| tst.js:110:9:110:12 | SINK | ExampleConfiguration | false | tst.js:110:9:110:12 | SINK | -| tst.js:110:14:110:14 | v | ExampleConfiguration | false | tst.js:110:14:110:14 | v | -| tst.js:116:13:116:18 | SOURCE | ExampleConfiguration | false | tst.js:116:13:116:18 | SOURCE | -| tst.js:117:5:117:8 | SINK | ExampleConfiguration | false | tst.js:117:5:117:8 | SINK | -| tst.js:117:10:117:10 | v | ExampleConfiguration | false | tst.js:117:10:117:10 | v | -| tst.js:119:9:119:9 | o | ExampleConfiguration | false | tst.js:119:9:119:9 | o | | tst.js:119:9:119:21 | o.includes(v) | ExampleConfiguration | true | tst.js:119:20:119:20 | v | -| tst.js:119:20:119:20 | v | ExampleConfiguration | false | tst.js:119:20:119:20 | v | -| tst.js:120:9:120:12 | SINK | ExampleConfiguration | false | tst.js:120:9:120:12 | SINK | -| tst.js:120:14:120:14 | v | ExampleConfiguration | false | tst.js:120:14:120:14 | v | -| tst.js:122:9:122:12 | SINK | ExampleConfiguration | false | tst.js:122:9:122:12 | SINK | -| tst.js:122:14:122:14 | v | ExampleConfiguration | false | tst.js:122:14:122:14 | v | -| tst.js:128:13:128:18 | SOURCE | ExampleConfiguration | false | tst.js:128:13:128:18 | SOURCE | -| tst.js:129:5:129:8 | SINK | ExampleConfiguration | false | tst.js:129:5:129:8 | SINK | -| tst.js:129:10:129:10 | v | ExampleConfiguration | false | tst.js:129:10:129:10 | v | -| tst.js:131:9:131:9 | o | ExampleConfiguration | false | tst.js:131:9:131:9 | o | | tst.js:131:9:131:27 | o.hasOwnProperty(v) | ExampleConfiguration | true | tst.js:131:26:131:26 | v | -| tst.js:131:26:131:26 | v | ExampleConfiguration | false | tst.js:131:26:131:26 | v | -| tst.js:132:9:132:12 | SINK | ExampleConfiguration | false | tst.js:132:9:132:12 | SINK | -| tst.js:132:14:132:14 | v | ExampleConfiguration | false | tst.js:132:14:132:14 | v | -| tst.js:133:16:133:16 | o | ExampleConfiguration | false | tst.js:133:16:133:16 | o | | tst.js:133:16:133:36 | o.hasOw ... ty(v.p) | ExampleConfiguration | true | tst.js:133:33:133:35 | v.p | -| tst.js:133:33:133:33 | v | ExampleConfiguration | false | tst.js:133:33:133:33 | v | -| tst.js:134:9:134:12 | SINK | ExampleConfiguration | false | tst.js:134:9:134:12 | SINK | -| tst.js:134:14:134:14 | v | ExampleConfiguration | false | tst.js:134:14:134:14 | v | -| tst.js:135:16:135:16 | o | ExampleConfiguration | false | tst.js:135:16:135:16 | o | | tst.js:135:16:135:38 | o.hasOw ... (v.p.q) | ExampleConfiguration | true | tst.js:135:33:135:37 | v.p.q | -| tst.js:135:33:135:33 | v | ExampleConfiguration | false | tst.js:135:33:135:33 | v | -| tst.js:136:9:136:12 | SINK | ExampleConfiguration | false | tst.js:136:9:136:12 | SINK | -| tst.js:136:14:136:14 | v | ExampleConfiguration | false | tst.js:136:14:136:14 | v | -| tst.js:137:16:137:16 | o | ExampleConfiguration | false | tst.js:137:16:137:16 | o | | tst.js:137:16:137:36 | o.hasOw ... ty(v.p) | ExampleConfiguration | true | tst.js:137:33:137:35 | v.p | -| tst.js:137:33:137:33 | v | ExampleConfiguration | false | tst.js:137:33:137:33 | v | -| tst.js:138:9:138:12 | SINK | ExampleConfiguration | false | tst.js:138:9:138:12 | SINK | -| tst.js:138:14:138:14 | v | ExampleConfiguration | false | tst.js:138:14:138:14 | v | -| tst.js:139:16:139:16 | o | ExampleConfiguration | false | tst.js:139:16:139:16 | o | | tst.js:139:16:139:41 | o.hasOw ... "p.q"]) | ExampleConfiguration | true | tst.js:139:33:139:40 | v["p.q"] | -| tst.js:139:33:139:33 | v | ExampleConfiguration | false | tst.js:139:33:139:33 | v | -| tst.js:140:9:140:12 | SINK | ExampleConfiguration | false | tst.js:140:9:140:12 | SINK | -| tst.js:140:14:140:14 | v | ExampleConfiguration | false | tst.js:140:14:140:14 | v | -| tst.js:145:13:145:18 | SOURCE | ExampleConfiguration | false | tst.js:145:13:145:18 | SOURCE | -| tst.js:146:5:146:8 | SINK | ExampleConfiguration | false | tst.js:146:5:146:8 | SINK | -| tst.js:146:10:146:10 | v | ExampleConfiguration | false | tst.js:146:10:146:10 | v | -| tst.js:148:9:148:9 | v | ExampleConfiguration | false | tst.js:148:9:148:9 | v | | tst.js:148:9:148:27 | v == "white-listed" | ExampleConfiguration | true | tst.js:148:9:148:9 | v | | tst.js:148:9:148:27 | v == "white-listed" | ExampleConfiguration | true | tst.js:148:14:148:27 | "white-listed" | -| tst.js:149:9:149:12 | SINK | ExampleConfiguration | false | tst.js:149:9:149:12 | SINK | -| tst.js:149:14:149:14 | v | ExampleConfiguration | false | tst.js:149:14:149:14 | v | -| tst.js:151:9:151:12 | SINK | ExampleConfiguration | false | tst.js:151:9:151:12 | SINK | -| tst.js:151:14:151:14 | v | ExampleConfiguration | false | tst.js:151:14:151:14 | v | | tst.js:154:9:154:27 | "white-listed" != v | ExampleConfiguration | false | tst.js:154:9:154:22 | "white-listed" | | tst.js:154:9:154:27 | "white-listed" != v | ExampleConfiguration | false | tst.js:154:27:154:27 | v | -| tst.js:154:27:154:27 | v | ExampleConfiguration | false | tst.js:154:27:154:27 | v | -| tst.js:155:9:155:12 | SINK | ExampleConfiguration | false | tst.js:155:9:155:12 | SINK | -| tst.js:155:14:155:14 | v | ExampleConfiguration | false | tst.js:155:14:155:14 | v | -| tst.js:157:9:157:12 | SINK | ExampleConfiguration | false | tst.js:157:9:157:12 | SINK | -| tst.js:157:14:157:14 | v | ExampleConfiguration | false | tst.js:157:14:157:14 | v | -| tst.js:160:9:160:9 | v | ExampleConfiguration | false | tst.js:160:9:160:9 | v | | tst.js:160:9:160:30 | v === " ... sted-1" | ExampleConfiguration | true | tst.js:160:9:160:9 | v | | tst.js:160:9:160:30 | v === " ... sted-1" | ExampleConfiguration | true | tst.js:160:15:160:30 | "white-listed-1" | -| tst.js:160:35:160:35 | v | ExampleConfiguration | false | tst.js:160:35:160:35 | v | | tst.js:160:35:160:56 | v === " ... sted-2" | ExampleConfiguration | true | tst.js:160:35:160:35 | v | | tst.js:160:35:160:56 | v === " ... sted-2" | ExampleConfiguration | true | tst.js:160:41:160:56 | "white-listed-2" | -| tst.js:161:9:161:12 | SINK | ExampleConfiguration | false | tst.js:161:9:161:12 | SINK | -| tst.js:161:14:161:14 | v | ExampleConfiguration | false | tst.js:161:14:161:14 | v | -| tst.js:163:9:163:12 | SINK | ExampleConfiguration | false | tst.js:163:9:163:12 | SINK | -| tst.js:163:14:163:14 | v | ExampleConfiguration | false | tst.js:163:14:163:14 | v | -| tst.js:166:9:166:9 | v | ExampleConfiguration | false | tst.js:166:9:166:9 | v | | tst.js:166:9:166:16 | v == !!0 | ExampleConfiguration | true | tst.js:166:9:166:9 | v | | tst.js:166:9:166:16 | v == !!0 | ExampleConfiguration | true | tst.js:166:14:166:16 | !!0 | -| tst.js:167:9:167:12 | SINK | ExampleConfiguration | false | tst.js:167:9:167:12 | SINK | -| tst.js:167:14:167:14 | v | ExampleConfiguration | false | tst.js:167:14:167:14 | v | -| tst.js:169:9:169:12 | SINK | ExampleConfiguration | false | tst.js:169:9:169:12 | SINK | -| tst.js:169:14:169:14 | v | ExampleConfiguration | false | tst.js:169:14:169:14 | v | -| tst.js:174:34:174:34 | x | ExampleConfiguration | false | tst.js:174:34:174:34 | x | -| tst.js:175:13:175:18 | SOURCE | ExampleConfiguration | false | tst.js:175:13:175:18 | SOURCE | -| tst.js:176:5:176:5 | v | ExampleConfiguration | false | tst.js:176:5:176:5 | v | -| tst.js:176:9:176:16 | SANITIZE | ExampleConfiguration | false | tst.js:176:9:176:16 | SANITIZE | -| tst.js:176:18:176:18 | v | ExampleConfiguration | false | tst.js:176:18:176:18 | v | -| tst.js:177:5:177:8 | SINK | ExampleConfiguration | false | tst.js:177:5:177:8 | SINK | -| tst.js:177:10:177:10 | v | ExampleConfiguration | false | tst.js:177:10:177:10 | v | -| tst.js:181:13:181:18 | SOURCE | ExampleConfiguration | false | tst.js:181:13:181:18 | SOURCE | -| tst.js:182:5:182:8 | SINK | ExampleConfiguration | false | tst.js:182:5:182:8 | SINK | -| tst.js:182:10:182:10 | v | ExampleConfiguration | false | tst.js:182:10:182:10 | v | | tst.js:184:9:184:21 | ~o.indexOf(v) | ExampleConfiguration | true | tst.js:184:20:184:20 | v | -| tst.js:184:10:184:10 | o | ExampleConfiguration | false | tst.js:184:10:184:10 | o | -| tst.js:184:20:184:20 | v | ExampleConfiguration | false | tst.js:184:20:184:20 | v | -| tst.js:185:9:185:12 | SINK | ExampleConfiguration | false | tst.js:185:9:185:12 | SINK | -| tst.js:185:14:185:14 | v | ExampleConfiguration | false | tst.js:185:14:185:14 | v | -| tst.js:187:9:187:12 | SINK | ExampleConfiguration | false | tst.js:187:9:187:12 | SINK | -| tst.js:187:14:187:14 | v | ExampleConfiguration | false | tst.js:187:14:187:14 | v | | tst.js:190:10:190:22 | ~o.indexOf(v) | ExampleConfiguration | true | tst.js:190:21:190:21 | v | -| tst.js:190:11:190:11 | o | ExampleConfiguration | false | tst.js:190:11:190:11 | o | -| tst.js:190:21:190:21 | v | ExampleConfiguration | false | tst.js:190:21:190:21 | v | -| tst.js:191:9:191:12 | SINK | ExampleConfiguration | false | tst.js:191:9:191:12 | SINK | -| tst.js:191:14:191:14 | v | ExampleConfiguration | false | tst.js:191:14:191:14 | v | -| tst.js:193:9:193:12 | SINK | ExampleConfiguration | false | tst.js:193:9:193:12 | SINK | -| tst.js:193:14:193:14 | v | ExampleConfiguration | false | tst.js:193:14:193:14 | v | -| tst.js:199:13:199:18 | SOURCE | ExampleConfiguration | false | tst.js:199:13:199:18 | SOURCE | -| tst.js:200:5:200:8 | SINK | ExampleConfiguration | false | tst.js:200:5:200:8 | SINK | -| tst.js:200:10:200:10 | v | ExampleConfiguration | false | tst.js:200:10:200:10 | v | -| tst.js:202:9:202:9 | o | ExampleConfiguration | false | tst.js:202:9:202:9 | o | | tst.js:202:9:202:26 | o.indexOf(v) <= -1 | ExampleConfiguration | false | tst.js:202:19:202:19 | v | -| tst.js:202:19:202:19 | v | ExampleConfiguration | false | tst.js:202:19:202:19 | v | -| tst.js:203:9:203:12 | SINK | ExampleConfiguration | false | tst.js:203:9:203:12 | SINK | -| tst.js:203:14:203:14 | v | ExampleConfiguration | false | tst.js:203:14:203:14 | v | -| tst.js:205:9:205:12 | SINK | ExampleConfiguration | false | tst.js:205:9:205:12 | SINK | -| tst.js:205:14:205:14 | v | ExampleConfiguration | false | tst.js:205:14:205:14 | v | -| tst.js:208:9:208:9 | o | ExampleConfiguration | false | tst.js:208:9:208:9 | o | | tst.js:208:9:208:25 | o.indexOf(v) >= 0 | ExampleConfiguration | true | tst.js:208:19:208:19 | v | -| tst.js:208:19:208:19 | v | ExampleConfiguration | false | tst.js:208:19:208:19 | v | -| tst.js:209:9:209:12 | SINK | ExampleConfiguration | false | tst.js:209:9:209:12 | SINK | -| tst.js:209:14:209:14 | v | ExampleConfiguration | false | tst.js:209:14:209:14 | v | -| tst.js:211:9:211:12 | SINK | ExampleConfiguration | false | tst.js:211:9:211:12 | SINK | -| tst.js:211:14:211:14 | v | ExampleConfiguration | false | tst.js:211:14:211:14 | v | -| tst.js:214:9:214:9 | o | ExampleConfiguration | false | tst.js:214:9:214:9 | o | | tst.js:214:9:214:24 | o.indexOf(v) < 0 | ExampleConfiguration | false | tst.js:214:19:214:19 | v | -| tst.js:214:19:214:19 | v | ExampleConfiguration | false | tst.js:214:19:214:19 | v | -| tst.js:215:9:215:12 | SINK | ExampleConfiguration | false | tst.js:215:9:215:12 | SINK | -| tst.js:215:14:215:14 | v | ExampleConfiguration | false | tst.js:215:14:215:14 | v | -| tst.js:217:9:217:12 | SINK | ExampleConfiguration | false | tst.js:217:9:217:12 | SINK | -| tst.js:217:14:217:14 | v | ExampleConfiguration | false | tst.js:217:14:217:14 | v | -| tst.js:220:9:220:9 | o | ExampleConfiguration | false | tst.js:220:9:220:9 | o | | tst.js:220:9:220:25 | o.indexOf(v) > -1 | ExampleConfiguration | true | tst.js:220:19:220:19 | v | -| tst.js:220:19:220:19 | v | ExampleConfiguration | false | tst.js:220:19:220:19 | v | -| tst.js:221:9:221:12 | SINK | ExampleConfiguration | false | tst.js:221:9:221:12 | SINK | -| tst.js:221:14:221:14 | v | ExampleConfiguration | false | tst.js:221:14:221:14 | v | -| tst.js:223:9:223:12 | SINK | ExampleConfiguration | false | tst.js:223:9:223:12 | SINK | -| tst.js:223:14:223:14 | v | ExampleConfiguration | false | tst.js:223:14:223:14 | v | | tst.js:226:9:226:26 | -1 >= o.indexOf(v) | ExampleConfiguration | false | tst.js:226:25:226:25 | v | -| tst.js:226:15:226:15 | o | ExampleConfiguration | false | tst.js:226:15:226:15 | o | -| tst.js:226:25:226:25 | v | ExampleConfiguration | false | tst.js:226:25:226:25 | v | -| tst.js:227:9:227:12 | SINK | ExampleConfiguration | false | tst.js:227:9:227:12 | SINK | -| tst.js:227:14:227:14 | v | ExampleConfiguration | false | tst.js:227:14:227:14 | v | -| tst.js:229:9:229:12 | SINK | ExampleConfiguration | false | tst.js:229:9:229:12 | SINK | -| tst.js:229:14:229:14 | v | ExampleConfiguration | false | tst.js:229:14:229:14 | v | -| tst.js:235:13:235:18 | SOURCE | ExampleConfiguration | false | tst.js:235:13:235:18 | SOURCE | -| tst.js:236:9:236:21 | isWhitelisted | ExampleConfiguration | false | tst.js:236:9:236:21 | isWhitelisted | | tst.js:236:9:236:24 | isWhitelisted(v) | ExampleConfiguration | true | tst.js:236:23:236:23 | v | -| tst.js:236:23:236:23 | v | ExampleConfiguration | false | tst.js:236:23:236:23 | v | -| tst.js:237:9:237:12 | SINK | ExampleConfiguration | false | tst.js:237:9:237:12 | SINK | -| tst.js:237:14:237:14 | v | ExampleConfiguration | false | tst.js:237:14:237:14 | v | -| tst.js:239:9:239:12 | SINK | ExampleConfiguration | false | tst.js:239:9:239:12 | SINK | -| tst.js:239:14:239:14 | v | ExampleConfiguration | false | tst.js:239:14:239:14 | v | -| tst.js:240:9:240:14 | config | ExampleConfiguration | false | tst.js:240:9:240:14 | config | | tst.js:240:9:240:28 | config.allowValue(v) | ExampleConfiguration | true | tst.js:240:27:240:27 | v | -| tst.js:240:27:240:27 | v | ExampleConfiguration | false | tst.js:240:27:240:27 | v | -| tst.js:241:9:241:12 | SINK | ExampleConfiguration | false | tst.js:241:9:241:12 | SINK | -| tst.js:241:14:241:14 | v | ExampleConfiguration | false | tst.js:241:14:241:14 | v | -| tst.js:243:9:243:12 | SINK | ExampleConfiguration | false | tst.js:243:9:243:12 | SINK | -| tst.js:243:14:243:14 | v | ExampleConfiguration | false | tst.js:243:14:243:14 | v | -| tst.js:248:13:248:18 | SOURCE | ExampleConfiguration | false | tst.js:248:13:248:18 | SOURCE | -| tst.js:249:5:249:8 | SINK | ExampleConfiguration | false | tst.js:249:5:249:8 | SINK | -| tst.js:249:10:249:10 | v | ExampleConfiguration | false | tst.js:249:10:249:10 | v | -| tst.js:252:16:252:24 | whitelist | ExampleConfiguration | false | tst.js:252:16:252:24 | whitelist | | tst.js:252:16:252:36 | whiteli ... ains(x) | ExampleConfiguration | true | tst.js:252:35:252:35 | x | -| tst.js:252:35:252:35 | x | ExampleConfiguration | false | tst.js:252:35:252:35 | x | -| tst.js:254:9:254:9 | f | ExampleConfiguration | false | tst.js:254:9:254:9 | f | -| tst.js:254:11:254:11 | v | ExampleConfiguration | false | tst.js:254:11:254:11 | v | -| tst.js:255:9:255:12 | SINK | ExampleConfiguration | false | tst.js:255:9:255:12 | SINK | -| tst.js:255:14:255:14 | v | ExampleConfiguration | false | tst.js:255:14:255:14 | v | -| tst.js:257:9:257:12 | SINK | ExampleConfiguration | false | tst.js:257:9:257:12 | SINK | -| tst.js:257:14:257:14 | v | ExampleConfiguration | false | tst.js:257:14:257:14 | v | -| tst.js:261:25:261:33 | whitelist | ExampleConfiguration | false | tst.js:261:25:261:33 | whitelist | | tst.js:261:25:261:45 | whiteli ... ains(y) | ExampleConfiguration | true | tst.js:261:44:261:44 | y | -| tst.js:261:44:261:44 | y | ExampleConfiguration | false | tst.js:261:44:261:44 | y | -| tst.js:262:16:262:24 | sanitized | ExampleConfiguration | false | tst.js:262:16:262:24 | sanitized | -| tst.js:264:9:264:9 | g | ExampleConfiguration | false | tst.js:264:9:264:9 | g | -| tst.js:264:11:264:11 | v | ExampleConfiguration | false | tst.js:264:11:264:11 | v | -| tst.js:265:9:265:12 | SINK | ExampleConfiguration | false | tst.js:265:9:265:12 | SINK | -| tst.js:265:14:265:14 | v | ExampleConfiguration | false | tst.js:265:14:265:14 | v | -| tst.js:267:9:267:12 | SINK | ExampleConfiguration | false | tst.js:267:9:267:12 | SINK | -| tst.js:267:14:267:14 | v | ExampleConfiguration | false | tst.js:267:14:267:14 | v | -| tst.js:271:25:271:33 | whitelist | ExampleConfiguration | false | tst.js:271:25:271:33 | whitelist | | tst.js:271:25:271:45 | whiteli ... ains(z) | ExampleConfiguration | true | tst.js:271:44:271:44 | z | -| tst.js:271:44:271:44 | z | ExampleConfiguration | false | tst.js:271:44:271:44 | z | -| tst.js:272:16:272:28 | somethingElse | ExampleConfiguration | false | tst.js:272:16:272:28 | somethingElse | -| tst.js:274:9:274:9 | h | ExampleConfiguration | false | tst.js:274:9:274:9 | h | -| tst.js:274:11:274:11 | v | ExampleConfiguration | false | tst.js:274:11:274:11 | v | -| tst.js:275:9:275:12 | SINK | ExampleConfiguration | false | tst.js:275:9:275:12 | SINK | -| tst.js:275:14:275:14 | v | ExampleConfiguration | false | tst.js:275:14:275:14 | v | -| tst.js:277:9:277:12 | SINK | ExampleConfiguration | false | tst.js:277:9:277:12 | SINK | -| tst.js:277:14:277:14 | v | ExampleConfiguration | false | tst.js:277:14:277:14 | v | -| tst.js:281:16:281:17 | x2 | ExampleConfiguration | false | tst.js:281:16:281:17 | x2 | | tst.js:281:16:281:25 | x2 != null | ExampleConfiguration | false | tst.js:281:16:281:17 | x2 | | tst.js:281:16:281:25 | x2 != null | ExampleConfiguration | false | tst.js:281:22:281:25 | null | -| tst.js:281:30:281:38 | whitelist | ExampleConfiguration | false | tst.js:281:30:281:38 | whitelist | | tst.js:281:30:281:51 | whiteli ... ins(x2) | ExampleConfiguration | true | tst.js:281:49:281:50 | x2 | -| tst.js:281:49:281:50 | x2 | ExampleConfiguration | false | tst.js:281:49:281:50 | x2 | -| tst.js:283:9:283:10 | f2 | ExampleConfiguration | false | tst.js:283:9:283:10 | f2 | -| tst.js:283:12:283:12 | v | ExampleConfiguration | false | tst.js:283:12:283:12 | v | -| tst.js:284:9:284:12 | SINK | ExampleConfiguration | false | tst.js:284:9:284:12 | SINK | -| tst.js:284:14:284:14 | v | ExampleConfiguration | false | tst.js:284:14:284:14 | v | -| tst.js:286:9:286:12 | SINK | ExampleConfiguration | false | tst.js:286:9:286:12 | SINK | -| tst.js:286:14:286:14 | v | ExampleConfiguration | false | tst.js:286:14:286:14 | v | -| tst.js:290:16:290:17 | x3 | ExampleConfiguration | false | tst.js:290:16:290:17 | x3 | | tst.js:290:16:290:25 | x3 == null | ExampleConfiguration | true | tst.js:290:16:290:17 | x3 | | tst.js:290:16:290:25 | x3 == null | ExampleConfiguration | true | tst.js:290:22:290:25 | null | -| tst.js:290:30:290:38 | whitelist | ExampleConfiguration | false | tst.js:290:30:290:38 | whitelist | | tst.js:290:30:290:51 | whiteli ... ins(x3) | ExampleConfiguration | true | tst.js:290:49:290:50 | x3 | -| tst.js:290:49:290:50 | x3 | ExampleConfiguration | false | tst.js:290:49:290:50 | x3 | -| tst.js:292:9:292:10 | f3 | ExampleConfiguration | false | tst.js:292:9:292:10 | f3 | -| tst.js:292:12:292:12 | v | ExampleConfiguration | false | tst.js:292:12:292:12 | v | -| tst.js:293:9:293:12 | SINK | ExampleConfiguration | false | tst.js:293:9:293:12 | SINK | -| tst.js:293:14:293:14 | v | ExampleConfiguration | false | tst.js:293:14:293:14 | v | -| tst.js:295:9:295:12 | SINK | ExampleConfiguration | false | tst.js:295:9:295:12 | SINK | -| tst.js:295:14:295:14 | v | ExampleConfiguration | false | tst.js:295:14:295:14 | v | -| tst.js:299:17:299:25 | whitelist | ExampleConfiguration | false | tst.js:299:17:299:25 | whitelist | | tst.js:299:17:299:38 | whiteli ... ins(x4) | ExampleConfiguration | true | tst.js:299:36:299:37 | x4 | -| tst.js:299:36:299:37 | x4 | ExampleConfiguration | false | tst.js:299:36:299:37 | x4 | -| tst.js:301:9:301:10 | f4 | ExampleConfiguration | false | tst.js:301:9:301:10 | f4 | -| tst.js:301:12:301:12 | v | ExampleConfiguration | false | tst.js:301:12:301:12 | v | -| tst.js:302:9:302:12 | SINK | ExampleConfiguration | false | tst.js:302:9:302:12 | SINK | -| tst.js:302:14:302:14 | v | ExampleConfiguration | false | tst.js:302:14:302:14 | v | -| tst.js:304:9:304:12 | SINK | ExampleConfiguration | false | tst.js:304:9:304:12 | SINK | -| tst.js:304:14:304:14 | v | ExampleConfiguration | false | tst.js:304:14:304:14 | v | -| tst.js:308:18:308:26 | whitelist | ExampleConfiguration | false | tst.js:308:18:308:26 | whitelist | | tst.js:308:18:308:39 | whiteli ... ins(x5) | ExampleConfiguration | true | tst.js:308:37:308:38 | x5 | -| tst.js:308:37:308:38 | x5 | ExampleConfiguration | false | tst.js:308:37:308:38 | x5 | -| tst.js:310:9:310:10 | f5 | ExampleConfiguration | false | tst.js:310:9:310:10 | f5 | -| tst.js:310:12:310:12 | v | ExampleConfiguration | false | tst.js:310:12:310:12 | v | -| tst.js:311:9:311:12 | SINK | ExampleConfiguration | false | tst.js:311:9:311:12 | SINK | -| tst.js:311:14:311:14 | v | ExampleConfiguration | false | tst.js:311:14:311:14 | v | -| tst.js:313:9:313:12 | SINK | ExampleConfiguration | false | tst.js:313:9:313:12 | SINK | -| tst.js:313:14:313:14 | v | ExampleConfiguration | false | tst.js:313:14:313:14 | v | -| tst.js:317:26:317:34 | whitelist | ExampleConfiguration | false | tst.js:317:26:317:34 | whitelist | | tst.js:317:26:317:47 | whiteli ... ins(x6) | ExampleConfiguration | true | tst.js:317:45:317:46 | x6 | -| tst.js:317:45:317:46 | x6 | ExampleConfiguration | false | tst.js:317:45:317:46 | x6 | -| tst.js:318:17:318:25 | sanitized | ExampleConfiguration | false | tst.js:318:17:318:25 | sanitized | -| tst.js:320:9:320:10 | f6 | ExampleConfiguration | false | tst.js:320:9:320:10 | f6 | -| tst.js:320:12:320:12 | v | ExampleConfiguration | false | tst.js:320:12:320:12 | v | -| tst.js:321:9:321:12 | SINK | ExampleConfiguration | false | tst.js:321:9:321:12 | SINK | -| tst.js:321:14:321:14 | v | ExampleConfiguration | false | tst.js:321:14:321:14 | v | -| tst.js:323:9:323:12 | SINK | ExampleConfiguration | false | tst.js:323:9:323:12 | SINK | -| tst.js:323:14:323:14 | v | ExampleConfiguration | false | tst.js:323:14:323:14 | v | -| tst.js:327:25:327:26 | x7 | ExampleConfiguration | false | tst.js:327:25:327:26 | x7 | | tst.js:327:25:327:34 | x7 != null | ExampleConfiguration | false | tst.js:327:25:327:26 | x7 | | tst.js:327:25:327:34 | x7 != null | ExampleConfiguration | false | tst.js:327:31:327:34 | null | -| tst.js:327:39:327:47 | whitelist | ExampleConfiguration | false | tst.js:327:39:327:47 | whitelist | | tst.js:327:39:327:60 | whiteli ... ins(x7) | ExampleConfiguration | true | tst.js:327:58:327:59 | x7 | -| tst.js:327:58:327:59 | x7 | ExampleConfiguration | false | tst.js:327:58:327:59 | x7 | -| tst.js:328:16:328:24 | sanitized | ExampleConfiguration | false | tst.js:328:16:328:24 | sanitized | -| tst.js:330:9:330:10 | f7 | ExampleConfiguration | false | tst.js:330:9:330:10 | f7 | -| tst.js:330:12:330:12 | v | ExampleConfiguration | false | tst.js:330:12:330:12 | v | -| tst.js:331:9:331:12 | SINK | ExampleConfiguration | false | tst.js:331:9:331:12 | SINK | -| tst.js:331:14:331:14 | v | ExampleConfiguration | false | tst.js:331:14:331:14 | v | -| tst.js:333:9:333:12 | SINK | ExampleConfiguration | false | tst.js:333:9:333:12 | SINK | -| tst.js:333:14:333:14 | v | ExampleConfiguration | false | tst.js:333:14:333:14 | v | -| tst.js:337:25:337:33 | whitelist | ExampleConfiguration | false | tst.js:337:25:337:33 | whitelist | | tst.js:337:25:337:46 | whiteli ... ins(x8) | ExampleConfiguration | true | tst.js:337:44:337:45 | x8 | -| tst.js:337:44:337:45 | x8 | ExampleConfiguration | false | tst.js:337:44:337:45 | x8 | -| tst.js:338:16:338:17 | x8 | ExampleConfiguration | false | tst.js:338:16:338:17 | x8 | | tst.js:338:16:338:25 | x8 != null | ExampleConfiguration | false | tst.js:338:16:338:17 | x8 | | tst.js:338:16:338:25 | x8 != null | ExampleConfiguration | false | tst.js:338:22:338:25 | null | -| tst.js:338:30:338:38 | sanitized | ExampleConfiguration | false | tst.js:338:30:338:38 | sanitized | -| tst.js:340:9:340:10 | f8 | ExampleConfiguration | false | tst.js:340:9:340:10 | f8 | -| tst.js:340:12:340:12 | v | ExampleConfiguration | false | tst.js:340:12:340:12 | v | -| tst.js:341:9:341:12 | SINK | ExampleConfiguration | false | tst.js:341:9:341:12 | SINK | -| tst.js:341:14:341:14 | v | ExampleConfiguration | false | tst.js:341:14:341:14 | v | -| tst.js:343:9:343:12 | SINK | ExampleConfiguration | false | tst.js:343:9:343:12 | SINK | -| tst.js:343:14:343:14 | v | ExampleConfiguration | false | tst.js:343:14:343:14 | v | -| tst.js:347:16:347:22 | unknown | ExampleConfiguration | false | tst.js:347:16:347:22 | unknown | -| tst.js:347:29:347:37 | whitelist | ExampleConfiguration | false | tst.js:347:29:347:37 | whitelist | | tst.js:347:29:347:50 | whiteli ... ins(x9) | ExampleConfiguration | true | tst.js:347:48:347:49 | x9 | -| tst.js:347:48:347:49 | x9 | ExampleConfiguration | false | tst.js:347:48:347:49 | x9 | -| tst.js:347:55:347:61 | unknown | ExampleConfiguration | false | tst.js:347:55:347:61 | unknown | -| tst.js:349:9:349:10 | f9 | ExampleConfiguration | false | tst.js:349:9:349:10 | f9 | -| tst.js:349:12:349:12 | v | ExampleConfiguration | false | tst.js:349:12:349:12 | v | -| tst.js:350:9:350:12 | SINK | ExampleConfiguration | false | tst.js:350:9:350:12 | SINK | -| tst.js:350:14:350:14 | v | ExampleConfiguration | false | tst.js:350:14:350:14 | v | -| tst.js:352:9:352:12 | SINK | ExampleConfiguration | false | tst.js:352:9:352:12 | SINK | -| tst.js:352:14:352:14 | v | ExampleConfiguration | false | tst.js:352:14:352:14 | v | -| tst.js:356:16:356:18 | x10 | ExampleConfiguration | false | tst.js:356:16:356:18 | x10 | | tst.js:356:16:356:27 | x10 !== null | ExampleConfiguration | false | tst.js:356:16:356:18 | x10 | | tst.js:356:16:356:27 | x10 !== null | ExampleConfiguration | false | tst.js:356:24:356:27 | null | -| tst.js:356:32:356:34 | x10 | ExampleConfiguration | false | tst.js:356:32:356:34 | x10 | | tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:32:356:34 | x10 | | tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:40:356:48 | undefined | -| tst.js:356:40:356:48 | undefined | ExampleConfiguration | false | tst.js:356:40:356:48 | undefined | -| tst.js:358:9:358:11 | f10 | ExampleConfiguration | false | tst.js:358:9:358:11 | f10 | -| tst.js:358:13:358:13 | v | ExampleConfiguration | false | tst.js:358:13:358:13 | v | -| tst.js:359:9:359:12 | SINK | ExampleConfiguration | false | tst.js:359:9:359:12 | SINK | -| tst.js:359:14:359:14 | v | ExampleConfiguration | false | tst.js:359:14:359:14 | v | -| tst.js:361:9:361:12 | SINK | ExampleConfiguration | false | tst.js:361:9:361:12 | SINK | -| tst.js:361:14:361:14 | v | ExampleConfiguration | false | tst.js:361:14:361:14 | v | -| tst.js:367:13:367:18 | SOURCE | ExampleConfiguration | false | tst.js:367:13:367:18 | SOURCE | -| tst.js:368:5:368:8 | SINK | ExampleConfiguration | false | tst.js:368:5:368:8 | SINK | -| tst.js:368:10:368:10 | o | ExampleConfiguration | false | tst.js:368:10:368:10 | o | -| tst.js:370:9:370:9 | o | ExampleConfiguration | false | tst.js:370:9:370:9 | o | | tst.js:370:9:370:29 | o.p == ... listed" | ExampleConfiguration | true | tst.js:370:9:370:11 | o.p | -| tst.js:371:9:371:12 | SINK | ExampleConfiguration | false | tst.js:371:9:371:12 | SINK | -| tst.js:371:14:371:14 | o | ExampleConfiguration | false | tst.js:371:14:371:14 | o | -| tst.js:373:9:373:12 | SINK | ExampleConfiguration | false | tst.js:373:9:373:12 | SINK | -| tst.js:373:14:373:14 | o | ExampleConfiguration | false | tst.js:373:14:373:14 | o | -| tst.js:376:19:376:19 | o | ExampleConfiguration | false | tst.js:376:19:376:19 | o | -| tst.js:377:11:377:11 | o | ExampleConfiguration | false | tst.js:377:11:377:11 | o | | tst.js:377:11:377:32 | o[p] == ... listed" | ExampleConfiguration | true | tst.js:377:11:377:14 | o[p] | -| tst.js:377:13:377:13 | p | ExampleConfiguration | false | tst.js:377:13:377:13 | p | -| tst.js:378:9:378:12 | SINK | ExampleConfiguration | false | tst.js:378:9:378:12 | SINK | -| tst.js:378:14:378:14 | o | ExampleConfiguration | false | tst.js:378:14:378:14 | o | -| tst.js:378:16:378:16 | p | ExampleConfiguration | false | tst.js:378:16:378:16 | p | -| tst.js:379:9:379:9 | p | ExampleConfiguration | false | tst.js:379:9:379:9 | p | -| tst.js:379:13:379:25 | somethingElse | ExampleConfiguration | false | tst.js:379:13:379:25 | somethingElse | -| tst.js:380:9:380:12 | SINK | ExampleConfiguration | false | tst.js:380:9:380:12 | SINK | -| tst.js:380:14:380:14 | o | ExampleConfiguration | false | tst.js:380:14:380:14 | o | -| tst.js:380:16:380:16 | p | ExampleConfiguration | false | tst.js:380:16:380:16 | p | -| tst.js:382:9:382:12 | SINK | ExampleConfiguration | false | tst.js:382:9:382:12 | SINK | -| tst.js:382:14:382:14 | o | ExampleConfiguration | false | tst.js:382:14:382:14 | o | -| tst.js:382:16:382:16 | p | ExampleConfiguration | false | tst.js:382:16:382:16 | p | From 4cad5549ee0088129bd37799e0a93ec6aa64034b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 18 Feb 2020 12:21:14 +0100 Subject: [PATCH 045/134] C++: Directly import AST GVN module in tests --- .../valuenumbering/GlobalValueNumbering/Uniqueness.ql | 2 +- .../valuenumbering/GlobalValueNumbering/diff_ir_expr.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.ql b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.ql index 5b020d757ee..bc6dbf94bf7 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.ql +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.ql @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl // Every expression should have exactly one GVN. // So this query should have zero results. diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.ql b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.ql index 317c3d97556..7b897f39dbd 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.ql +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.ql @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.valuenumbering.GlobalValueNumbering as AST +import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl as AST import semmle.code.cpp.ir.internal.ASTValueNumbering as IR import semmle.code.cpp.ir.IR From c3b88210aaf35a5a4860985975c66f76ca5ecf26 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 12 Nov 2019 14:00:34 +0000 Subject: [PATCH 046/134] C#: Add runtime idenfitiers to project files. --- .../Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj | 1 + csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj | 1 + .../Semmle.Extraction.CIL.Driver.csproj | 1 + .../extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj | 1 + .../Semmle.Extraction.CSharp.Driver.csproj | 1 + .../Semmle.Extraction.CSharp.Standalone.csproj | 1 + .../Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj | 1 + .../Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj | 1 + csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj | 1 + csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj | 1 + csharp/extractor/Semmle.Util/Semmle.Util.csproj | 1 + 11 files changed, 11 insertions(+) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj index ef4a016e20b..547aaa570b4 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj @@ -4,6 +4,7 @@ Exe netcoreapp3.0 false + win-x64;linux-x64;osx-x64 diff --git a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj b/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj index 089369c38e3..5e3f2295ad0 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj +++ b/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj @@ -8,6 +8,7 @@ Exe false + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj b/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj index a11aeefa7ae..e7f87c7b36b 100644 --- a/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj @@ -6,6 +6,7 @@ Semmle.Extraction.CIL.Driver Semmle.Extraction.CIL.Driver false + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj index 131c49c845b..9db880787b0 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj +++ b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj @@ -6,6 +6,7 @@ Semmle.Extraction.CIL false true + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj index 9113890ddf7..7475350f993 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj @@ -6,6 +6,7 @@ Semmle.Extraction.CSharp.Driver Semmle.Extraction.CSharp.Driver false + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj index 5277e352f4c..4cf0274b737 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj @@ -9,6 +9,7 @@ true false + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj index 5b8e3961ad6..87234841c5f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj @@ -6,6 +6,7 @@ Semmle.Extraction.CSharp false true + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj index b003709e37a..c101a5fba83 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj +++ b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj @@ -4,6 +4,7 @@ Exe netcoreapp3.0 false + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj index a3387c16065..48e2a00c9f3 100644 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj +++ b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj @@ -6,6 +6,7 @@ Semmle.Extraction false Semmle.Extraction.ruleset + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj index 45f28343e67..d0ef95a4d4c 100644 --- a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj +++ b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj @@ -4,6 +4,7 @@ Exe netcoreapp3.0 false + win-x64;linux-x64;osx-x64 diff --git a/csharp/extractor/Semmle.Util/Semmle.Util.csproj b/csharp/extractor/Semmle.Util/Semmle.Util.csproj index 4d35dcae079..4ef3eda35d9 100644 --- a/csharp/extractor/Semmle.Util/Semmle.Util.csproj +++ b/csharp/extractor/Semmle.Util/Semmle.Util.csproj @@ -5,6 +5,7 @@ Semmle.Util Semmle.Util false + win-x64;linux-x64;osx-x64 From 9e3ed214d0f34ee90d554874cc3e82d00b8ba2ff Mon Sep 17 00:00:00 2001 From: Rebecca Valentine <171941+BekaValentine@users.noreply.github.com> Date: Tue, 18 Feb 2020 21:29:20 -0800 Subject: [PATCH 047/134] Python: ObjectAPI to ValueAPI: Foresight Additions (#2819) * Adds the...Type() predicates as foresight modernizations. * Removes predicates that are not currently ported/portable * Adds range types * Update python/ql/src/semmle/python/objects/ObjectAPI.qll Co-Authored-By: Rasmus Wriedt Larsen * Update python/ql/src/semmle/python/objects/ObjectAPI.qll Co-Authored-By: Rasmus Wriedt Larsen * Swaps xType for just x, at least when it's new Co-authored-by: Rasmus Wriedt Larsen --- .../src/semmle/python/objects/ObjectAPI.qll | 149 +++++++++++++++--- 1 file changed, 131 insertions(+), 18 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index a4a93a88d7d..1f1f7001da1 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -698,40 +698,57 @@ module ClassValue { ClassValue bool() { result = TBuiltinClassObject(Builtin::special("bool")) } - + + /** Get the `ClassValue` for the `tuple` class. */ + ClassValue tuple() { + result = TBuiltinClassObject(Builtin::special("tuple")) + } + + /** Get the `ClassValue` for the `list` class. */ + ClassValue list() { + result = TBuiltinClassObject(Builtin::special("list")) + } + + /** Get the `ClassValue` for `xrange` (Python 2), or `range` (only Python 3) */ + ClassValue range() { + major_version() = 2 and result = TBuiltinClassObject(Builtin::special("xrange")) + or + major_version() = 3 and result = TBuiltinClassObject(Builtin::special("range")) + } + /** Get the `ClassValue` for the `dict` class. */ ClassValue dict() { result = TBuiltinClassObject(Builtin::special("dict")) } - - /** Get the `ClassValue` for the class of Python functions. */ - ClassValue function() { - result = TBuiltinClassObject(Builtin::special("FunctionType")) + + /** Get the `ClassValue` for the `set` class. */ + ClassValue set() { + result = TBuiltinClassObject(Builtin::special("set")) } - - /** Get the `ClassValue` for the `type` class. */ - ClassValue type() { - result = TType() - } - - /** Get the `ClassValue` for the class of builtin functions. */ - ClassValue builtinFunction() { - result = Value::named("len").getClass() + + /** Get the `ClassValue` for the `object` class. */ + ClassValue object() { + result = TBuiltinClassObject(Builtin::special("object")) } /** Get the `ClassValue` for the `int` class. */ ClassValue int_() { result = TBuiltinClassObject(Builtin::special("int")) } + + /** Get the `ClassValue` for the `long` class. */ + ClassValue long() { + result = TBuiltinClassObject(Builtin::special("long")) + } /** Get the `ClassValue` for the `float` class. */ ClassValue float_() { result = TBuiltinClassObject(Builtin::special("float")) } - - /** Get the `ClassValue` for the `list` class. */ - ClassValue list() { - result = TBuiltinClassObject(Builtin::special("list")) + + /** Get the `ClassValue` for the `complex` class. */ + ClassValue complex() { + result = TBuiltinClassObject(Builtin::special("complex")) } /** Get the `ClassValue` for the `bytes` class (also called `str` in Python 2). */ @@ -753,7 +770,47 @@ module ClassValue { else result = unicode() } + + /** Get the `ClassValue` for the `property` class. */ + ClassValue property() { + result = TBuiltinClassObject(Builtin::special("property")) + } + + /** Get the `ClassValue` for the class of Python functions. */ + ClassValue functionType() { + result = TBuiltinClassObject(Builtin::special("FunctionType")) + } + /** Get the `ClassValue` for the class of builtin functions. */ + ClassValue builtinFunction() { + result = Value::named("len").getClass() + } + + /** Get the `ClassValue` for the `generatorType` class. */ + ClassValue generator() { + result = TBuiltinClassObject(Builtin::special("generator")) + } + + /** Get the `ClassValue` for the `type` class. */ + ClassValue type() { + result = TType() + } + + /** Get the `ClassValue` for `ClassType`. */ + ClassValue classType() { + result = TBuiltinClassObject(Builtin::special("ClassType")) + } + + /** Get the `ClassValue` for `InstanceType`. */ + ClassValue instanceType() { + result = TBuiltinClassObject(Builtin::special("InstanceType")) + } + + /** Get the `ClassValue` for `super`. */ + ClassValue super_() { + result = TBuiltinClassObject(Builtin::special("super")) + } + /** Get the `ClassValue` for the `classmethod` class. */ ClassValue classmethod() { result = TBuiltinClassObject(Builtin::special("ClassMethod")) @@ -763,21 +820,77 @@ module ClassValue { ClassValue staticmethod() { result = TBuiltinClassObject(Builtin::special("StaticMethod")) } + + /** Get the `ClassValue` for the `MethodType` class. */ + pragma [noinline] + ClassValue methodType() { + result = TBuiltinClassObject(Builtin::special("MethodType")) + } + + /** Get the `ClassValue` for the `MethodDescriptorType` class. */ + ClassValue methodDescriptorType() { + result = TBuiltinClassObject(Builtin::special("MethodDescriptorType")) + } + + /** Get the `ClassValue` for the `GetSetDescriptorType` class. */ + ClassValue getSetDescriptorType() { + result = TBuiltinClassObject(Builtin::special("GetSetDescriptorType")) + } + + /** Get the `ClassValue` for the `StopIteration` class. */ + ClassValue stopIteration() { + result = TBuiltinClassObject(Builtin::special("StopIteration")) + } /** Get the `ClassValue` for the class of modules. */ ClassValue module_() { result = TBuiltinClassObject(Builtin::special("ModuleType")) } + /** Get the `ClassValue` for the `Exception` class. */ + ClassValue exception() { + result = TBuiltinClassObject(Builtin::special("Exception")) + } + + /** Get the `ClassValue` for the `BaseException` class. */ + ClassValue baseException() { + result = TBuiltinClassObject(Builtin::special("BaseException")) + } + /** Get the `ClassValue` for the `NoneType` class. */ ClassValue nonetype() { result = TBuiltinClassObject(Builtin::special("NoneType")) } + + /** Get the `ClassValue` for the `TypeError` class */ + ClassValue typeError() { + result = TBuiltinClassObject(Builtin::special("TypeError")) + } /** Get the `ClassValue` for the `NameError` class. */ ClassValue nameError() { result = TBuiltinClassObject(Builtin::builtin("NameError")) } + + /** Get the `ClassValue` for the `AttributeError` class. */ + ClassValue attributeError() { + result = TBuiltinClassObject(Builtin::builtin("AttributeError")) + } + + /** Get the `ClassValue` for the `KeyError` class. */ + ClassValue keyError() { + result = TBuiltinClassObject(Builtin::builtin("KeyError")) + } + + /** Get the `ClassValue` for the `IOError` class. */ + ClassValue ioError() { + result = TBuiltinClassObject(Builtin::builtin("IOError")) + } + + /** Get the `ClassValue` for the `NotImplementedError` class. */ + ClassValue notImplementedError() { + result = TBuiltinClassObject(Builtin::builtin("NotImplementedError")) + } /** Get the `ClassValue` for the `ImportError` class. */ ClassValue importError() { From 4346691cdcdf16cf6d83d5a7467c9de57cbff328 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 14 Feb 2020 14:08:31 +0000 Subject: [PATCH 048/134] JavaScript: Distinguish `{lo}` and `{lo,}` in the regular expression parser. --- .../src/com/semmle/js/extractor/Main.java | 2 +- .../src/com/semmle/js/parser/RegExpParser.java | 15 +++++++++++++-- .../tests/exprs/output/trap/regexp.js.trap | 5 +++++ javascript/ql/src/semmle/javascript/Regexp.qll | 14 +++++++++++--- .../library-tests/RegExp/Bounds/Bounds.expected | 4 ++++ .../ql/test/library-tests/RegExp/Bounds/Bounds.ql | 7 +++++++ .../ql/test/library-tests/RegExp/Bounds/tst.js | 4 ++++ 7 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 javascript/ql/test/library-tests/RegExp/Bounds/Bounds.expected create mode 100644 javascript/ql/test/library-tests/RegExp/Bounds/Bounds.ql create mode 100644 javascript/ql/test/library-tests/RegExp/Bounds/tst.js diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 00e9dee9f9e..81e25eb23e0 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -37,7 +37,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2020-02-05"; + public static final String EXTRACTOR_VERSION = "2020-02-14"; public static final Pattern NEWLINE = Pattern.compile("\n"); diff --git a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java index 0f6ef74972c..c211120ae73 100644 --- a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java @@ -281,8 +281,19 @@ public class RegExpParser { if (this.match("+")) return this.finishTerm(new Plus(loc, atom, !this.match("?"))); if (this.match("?")) return this.finishTerm(new Opt(loc, atom, !this.match("?"))); if (this.match("{")) { - Double lo = toNumber(this.readDigits(false)), hi = null; - if (this.match(",") && !this.lookahead("}")) hi = toNumber(this.readDigits(false)); + Double lo = toNumber(this.readDigits(false)), hi; + if (this.match(",")) { + if (!this.lookahead("}")) { + // atom{lo, hi} + hi = toNumber(this.readDigits(false)); + } else { + // atom{lo,} + hi = null; + } + } else { + // atom{lo} + hi = lo; + } this.expectRBrace(); return this.finishTerm(new Range(loc, atom, !this.match("?"), lo, hi)); } diff --git a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap index b8958389d6b..84dd57d3a17 100644 --- a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap @@ -1088,6 +1088,7 @@ locations_default(#20376,#10000,15,2,15,5) hasLocation(#20375,#20376) isGreedy(#20375) rangeQuantifierLowerBound(#20375,1) +rangeQuantifierUpperBound(#20375,1) #20377=* regexpterm(#20377,14,#20375,0,"a") #20378=@"loc,{#10000},15,2,15,2" @@ -1157,6 +1158,7 @@ regexpterm(#20393,11,#20392,0,"a{1}?") locations_default(#20394,#10000,18,2,18,6) hasLocation(#20393,#20394) rangeQuantifierLowerBound(#20393,1) +rangeQuantifierUpperBound(#20393,1) #20395=* regexpterm(#20395,14,#20393,0,"a") #20396=@"loc,{#10000},18,2,18,2" @@ -1670,6 +1672,7 @@ locations_default(#20543,#10000,37,2,37,3) hasLocation(#20542,#20543) isGreedy(#20542) rangeQuantifierLowerBound(#20542,0) +rangeQuantifierUpperBound(#20542,0) #20544=* regexpterm(#20544,14,#20542,0,"a") #20545=@"loc,{#10000},37,2,37,2" @@ -1708,6 +1711,7 @@ locations_default(#20555,#10000,38,2,38,3) hasLocation(#20554,#20555) isGreedy(#20554) rangeQuantifierLowerBound(#20554,0) +rangeQuantifierUpperBound(#20554,0) #20556=* regexpterm(#20556,14,#20554,0,"a") #20557=@"loc,{#10000},38,2,38,2" @@ -1754,6 +1758,7 @@ locations_default(#20569,#10000,39,2,39,4) hasLocation(#20568,#20569) isGreedy(#20568) rangeQuantifierLowerBound(#20568,2) +rangeQuantifierUpperBound(#20568,2) #20570=* regexpterm(#20570,14,#20568,0,"a") #20571=@"loc,{#10000},39,2,39,2" diff --git a/javascript/ql/src/semmle/javascript/Regexp.qll b/javascript/ql/src/semmle/javascript/Regexp.qll index 29e5a1bae3e..a5346f2caa9 100644 --- a/javascript/ql/src/semmle/javascript/Regexp.qll +++ b/javascript/ql/src/semmle/javascript/Regexp.qll @@ -506,17 +506,25 @@ class RegExpOpt extends RegExpQuantifier, @regexp_opt { /** * A range-quantified term * - * Example: + * Examples: * * ``` * \w{2,4} + * \w{2,} + * \w{2} * ``` */ class RegExpRange extends RegExpQuantifier, @regexp_range { - /** Gets the lower bound of the range, if any. */ + /** Gets the lower bound of the range. */ int getLowerBound() { rangeQuantifierLowerBound(this, result) } - /** Gets the upper bound of the range, if any. */ + /** + * Gets the upper bound of the range, if any. + * + * If there is no upper bound, any number of repetitions is allowed. + * For a term of the form `r{lo}`, both the lower and the upper bound + * are `lo`. + */ int getUpperBound() { rangeQuantifierUpperBound(this, result) } override predicate isNullable() { diff --git a/javascript/ql/test/library-tests/RegExp/Bounds/Bounds.expected b/javascript/ql/test/library-tests/RegExp/Bounds/Bounds.expected new file mode 100644 index 00000000000..44a0433869a --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/Bounds/Bounds.expected @@ -0,0 +1,4 @@ +| tst.js:1:2:1:5 | a{1} | 1 | 1 | +| tst.js:2:2:2:6 | a{1,} | 1 | | +| tst.js:3:2:3:7 | a{1,5} | 1 | 5 | +| tst.js:4:2:4:6 | a{,5} | 0 | 5 | diff --git a/javascript/ql/test/library-tests/RegExp/Bounds/Bounds.ql b/javascript/ql/test/library-tests/RegExp/Bounds/Bounds.ql new file mode 100644 index 00000000000..2e31a8ab3ce --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/Bounds/Bounds.ql @@ -0,0 +1,7 @@ +import javascript + +from RegExpRange rr, string lb, string ub +where + lb = rr.getLowerBound().toString() and + if exists(rr.getUpperBound()) then ub = rr.getUpperBound().toString() else ub = "" +select rr, lb, ub diff --git a/javascript/ql/test/library-tests/RegExp/Bounds/tst.js b/javascript/ql/test/library-tests/RegExp/Bounds/tst.js new file mode 100644 index 00000000000..4a92bc55edb --- /dev/null +++ b/javascript/ql/test/library-tests/RegExp/Bounds/tst.js @@ -0,0 +1,4 @@ +/a{1}/; +/a{1,}/; +/a{1,5}/; +/a{,5}/; From 77105f657263b3726a9a66444035e85b7ca9aec4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 19 Feb 2020 09:30:03 +0000 Subject: [PATCH 049/134] JS: Do not flag void operands MissingAwait --- javascript/ql/src/Expressions/MissingAwait.ql | 5 ++++- .../ql/test/query-tests/Expressions/MissingAwait/tst.js | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Expressions/MissingAwait.ql b/javascript/ql/src/Expressions/MissingAwait.ql index f6a446e43c2..be40eef0d4b 100644 --- a/javascript/ql/src/Expressions/MissingAwait.ql +++ b/javascript/ql/src/Expressions/MissingAwait.ql @@ -43,7 +43,10 @@ predicate isBadPromiseContext(Expr expr) { or expr = any(LogicalBinaryExpr e).getLeftOperand() or - expr = any(UnaryExpr e).getOperand() + exists(UnaryExpr e | + expr = e.getOperand() and + not e instanceof VoidExpr + ) or expr = any(UpdateExpr e).getOperand() or diff --git a/javascript/ql/test/query-tests/Expressions/MissingAwait/tst.js b/javascript/ql/test/query-tests/Expressions/MissingAwait/tst.js index 7675f196b08..23909124b41 100644 --- a/javascript/ql/test/query-tests/Expressions/MissingAwait/tst.js +++ b/javascript/ql/test/query-tests/Expressions/MissingAwait/tst.js @@ -61,3 +61,7 @@ function useThingPossiblySync(b) { return thing + "bar"; // NOT OK - but we don't flag it } + +function useThingInVoid() { + void getThing(); // OK +} From 3a05a82c1de6f30c139023fb6c2676612ab5020c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 19 Feb 2020 10:35:03 +0100 Subject: [PATCH 050/134] C++: Accept output --- .../GlobalValueNumbering/Uniqueness.expected | 58 ------- .../diff_ir_expr.expected | 142 ++++++++++++++++++ 2 files changed, 142 insertions(+), 58 deletions(-) diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.expected index 0aebaa26f60..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.expected @@ -1,58 +0,0 @@ -| test.cpp:5:3:5:13 | ... = ... | | -| test.cpp:6:3:6:13 | ... = ... | | -| test.cpp:7:3:7:7 | ... = ... | | -| test.cpp:10:16:10:16 | 1 | | -| test.cpp:16:3:16:24 | ... = ... | | -| test.cpp:17:3:17:24 | ... = ... | | -| test.cpp:18:3:18:7 | ... = ... | | -| test.cpp:21:16:21:16 | 2 | | -| test.cpp:29:3:29:24 | ... = ... | | -| test.cpp:30:3:30:17 | call to change_global02 | | -| test.cpp:31:3:31:24 | ... = ... | | -| test.cpp:32:3:32:7 | ... = ... | | -| test.cpp:35:16:35:16 | 3 | | -| test.cpp:43:3:43:24 | ... = ... | | -| test.cpp:44:3:44:9 | ... = ... | | -| test.cpp:45:3:45:24 | ... = ... | | -| test.cpp:46:3:46:7 | ... = ... | | -| test.cpp:51:25:51:25 | (unsigned int)... | | -| test.cpp:53:10:53:13 | (int)... | | -| test.cpp:53:10:53:13 | * ... | LoadTotalOverlap, Unary | -| test.cpp:53:18:53:21 | (int)... | | -| test.cpp:55:5:55:15 | ... = ... | | -| test.cpp:56:12:56:25 | (...) | | -| test.cpp:56:12:56:43 | ... && ... | | -| test.cpp:56:13:56:16 | (int)... | | -| test.cpp:56:13:56:16 | * ... | Unary, Unique | -| test.cpp:56:21:56:24 | (int)... | | -| test.cpp:56:21:56:24 | * ... | LoadTotalOverlap, Unary | -| test.cpp:56:30:56:43 | (...) | | -| test.cpp:56:31:56:34 | (int)... | | -| test.cpp:56:31:56:34 | * ... | Unary, Unique | -| test.cpp:56:39:56:42 | (int)... | | -| test.cpp:56:47:56:51 | ... ++ | | -| test.cpp:59:9:59:12 | (int)... | | -| test.cpp:59:9:59:12 | * ... | Unary, Unique | -| test.cpp:59:17:59:20 | (int)... | | -| test.cpp:62:5:62:12 | ... ++ | | -| test.cpp:77:20:77:28 | call to getAValue | Unary, Unique | -| test.cpp:77:20:77:30 | (signed short)... | | -| test.cpp:79:7:79:7 | (int)... | | -| test.cpp:79:7:79:7 | v | Unary, Unary | -| test.cpp:79:11:79:20 | (int)... | | -| test.cpp:79:17:79:20 | val1 | LoadTotalOverlap, Unary | -| test.cpp:79:24:79:33 | (int)... | | -| test.cpp:79:30:79:33 | val2 | LoadTotalOverlap, Unary | -| test.cpp:80:5:80:19 | ... = ... | | -| test.cpp:80:9:80:17 | call to getAValue | Unary, Unique | -| test.cpp:80:9:80:19 | (signed short)... | | -| test.cpp:88:3:88:20 | ... = ... | | -| test.cpp:88:12:88:12 | (void *)... | | -| test.cpp:105:11:105:12 | (Base *)... | | -| test.cpp:105:11:105:12 | pd | InheritanceConversion, InitializeParameter | -| test.cpp:106:14:106:35 | static_cast... | | -| test.cpp:106:33:106:34 | pd | InheritanceConversion, InitializeParameter | -| test.cpp:128:3:128:11 | ... = ... | | -| test.cpp:139:3:139:24 | ... = ... | | -| test.cpp:147:3:147:18 | ... = ... | | -| test.cpp:156:3:156:17 | ... = ... | | diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected index e69de29bb2d..cd44eb8572b 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected @@ -0,0 +1,142 @@ +| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only | +| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only | +| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only | +| test.cpp:10:16:10:16 | 1 | test.cpp:10:16:10:16 | 1 | AST only | +| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only | +| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only | +| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only | +| test.cpp:21:16:21:16 | 2 | test.cpp:21:16:21:16 | 2 | AST only | +| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only | +| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only | +| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only | +| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only | +| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only | +| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only | +| test.cpp:35:16:35:16 | 3 | test.cpp:35:16:35:16 | 3 | AST only | +| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only | +| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only | +| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only | +| test.cpp:43:7:43:24 | ... + ... | test.cpp:46:7:46:7 | x | IR only | +| test.cpp:43:17:43:24 | global03 | test.cpp:45:17:45:24 | global03 | IR only | +| test.cpp:44:3:44:5 | * ... | test.cpp:44:4:44:5 | p2 | IR only | +| test.cpp:44:3:44:9 | ... = ... | test.cpp:44:3:44:9 | ... = ... | AST only | +| test.cpp:44:4:44:5 | p2 | test.cpp:44:3:44:5 | * ... | IR only | +| test.cpp:44:9:44:9 | 0 | test.cpp:51:25:51:25 | 0 | AST only | +| test.cpp:44:9:44:9 | 0 | test.cpp:53:18:53:21 | (int)... | AST only | +| test.cpp:44:9:44:9 | 0 | test.cpp:56:39:56:42 | (int)... | AST only | +| test.cpp:44:9:44:9 | 0 | test.cpp:59:17:59:20 | (int)... | AST only | +| test.cpp:44:9:44:9 | 0 | test.cpp:88:12:88:12 | 0 | AST only | +| test.cpp:45:3:45:3 | x | test.cpp:43:3:43:3 | x | IR only | +| test.cpp:45:3:45:24 | ... = ... | test.cpp:45:3:45:24 | ... = ... | AST only | +| test.cpp:45:7:45:24 | ... + ... | test.cpp:43:7:43:24 | ... + ... | IR only | +| test.cpp:45:17:45:24 | global03 | test.cpp:43:17:43:24 | global03 | IR only | +| test.cpp:46:3:46:7 | ... = ... | test.cpp:46:3:46:7 | ... = ... | AST only | +| test.cpp:46:7:46:7 | x | test.cpp:43:7:43:24 | ... + ... | IR only | +| test.cpp:51:25:51:25 | 0 | test.cpp:44:9:44:9 | 0 | AST only | +| test.cpp:51:25:51:25 | 0 | test.cpp:53:18:53:21 | (int)... | AST only | +| test.cpp:51:25:51:25 | 0 | test.cpp:56:39:56:42 | (int)... | AST only | +| test.cpp:51:25:51:25 | 0 | test.cpp:59:17:59:20 | (int)... | AST only | +| test.cpp:51:25:51:25 | 0 | test.cpp:88:12:88:12 | 0 | AST only | +| test.cpp:51:25:51:25 | (unsigned int)... | test.cpp:51:25:51:25 | (unsigned int)... | AST only | +| test.cpp:53:10:53:13 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only | +| test.cpp:53:10:53:13 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only | +| test.cpp:53:18:53:21 | (int)... | test.cpp:44:9:44:9 | 0 | AST only | +| test.cpp:53:18:53:21 | (int)... | test.cpp:51:25:51:25 | 0 | AST only | +| test.cpp:53:18:53:21 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only | +| test.cpp:53:18:53:21 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only | +| test.cpp:53:18:53:21 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only | +| test.cpp:53:18:53:21 | (int)... | test.cpp:88:12:88:12 | 0 | AST only | +| test.cpp:55:5:55:15 | ... = ... | test.cpp:55:5:55:15 | ... = ... | AST only | +| test.cpp:56:12:56:25 | (...) | test.cpp:56:12:56:25 | (...) | AST only | +| test.cpp:56:12:56:43 | ... && ... | test.cpp:56:12:56:43 | ... && ... | AST only | +| test.cpp:56:13:56:16 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only | +| test.cpp:56:13:56:16 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only | +| test.cpp:56:13:56:16 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only | +| test.cpp:56:13:56:16 | * ... | test.cpp:56:31:56:34 | * ... | AST only | +| test.cpp:56:13:56:16 | * ... | test.cpp:59:9:59:12 | * ... | AST only | +| test.cpp:56:21:56:24 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only | +| test.cpp:56:21:56:24 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only | +| test.cpp:56:30:56:43 | (...) | test.cpp:56:30:56:43 | (...) | AST only | +| test.cpp:56:31:56:34 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only | +| test.cpp:56:31:56:34 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only | +| test.cpp:56:31:56:34 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only | +| test.cpp:56:31:56:34 | * ... | test.cpp:56:13:56:16 | * ... | AST only | +| test.cpp:56:31:56:34 | * ... | test.cpp:59:9:59:12 | * ... | AST only | +| test.cpp:56:39:56:42 | (int)... | test.cpp:44:9:44:9 | 0 | AST only | +| test.cpp:56:39:56:42 | (int)... | test.cpp:51:25:51:25 | 0 | AST only | +| test.cpp:56:39:56:42 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only | +| test.cpp:56:39:56:42 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only | +| test.cpp:56:39:56:42 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only | +| test.cpp:56:39:56:42 | (int)... | test.cpp:88:12:88:12 | 0 | AST only | +| test.cpp:56:47:56:51 | ... ++ | test.cpp:56:47:56:51 | ... ++ | AST only | +| test.cpp:59:9:59:12 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only | +| test.cpp:59:9:59:12 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only | +| test.cpp:59:9:59:12 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only | +| test.cpp:59:9:59:12 | * ... | test.cpp:56:13:56:16 | * ... | AST only | +| test.cpp:59:9:59:12 | * ... | test.cpp:56:31:56:34 | * ... | AST only | +| test.cpp:59:17:59:20 | (int)... | test.cpp:44:9:44:9 | 0 | AST only | +| test.cpp:59:17:59:20 | (int)... | test.cpp:51:25:51:25 | 0 | AST only | +| test.cpp:59:17:59:20 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only | +| test.cpp:59:17:59:20 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only | +| test.cpp:59:17:59:20 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only | +| test.cpp:59:17:59:20 | (int)... | test.cpp:88:12:88:12 | 0 | AST only | +| test.cpp:62:5:62:12 | ... ++ | test.cpp:62:5:62:12 | ... ++ | AST only | +| test.cpp:77:20:77:28 | call to getAValue | test.cpp:79:7:79:7 | v | IR only | +| test.cpp:77:20:77:30 | (signed short)... | test.cpp:77:20:77:30 | (signed short)... | AST only | +| test.cpp:77:20:77:30 | (signed short)... | test.cpp:79:7:79:7 | v | AST only | +| test.cpp:79:7:79:7 | (int)... | test.cpp:79:7:79:7 | (int)... | AST only | +| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:28 | call to getAValue | IR only | +| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:30 | (signed short)... | AST only | +| test.cpp:79:11:79:20 | (int)... | test.cpp:79:11:79:20 | (int)... | AST only | +| test.cpp:79:24:79:33 | (int)... | test.cpp:79:24:79:33 | (int)... | AST only | +| test.cpp:80:5:80:19 | ... = ... | test.cpp:80:5:80:19 | ... = ... | AST only | +| test.cpp:80:9:80:19 | (signed short)... | test.cpp:80:9:80:19 | (signed short)... | AST only | +| test.cpp:88:3:88:20 | ... = ... | test.cpp:88:3:88:20 | ... = ... | AST only | +| test.cpp:88:12:88:12 | 0 | test.cpp:44:9:44:9 | 0 | AST only | +| test.cpp:88:12:88:12 | 0 | test.cpp:51:25:51:25 | 0 | AST only | +| test.cpp:88:12:88:12 | 0 | test.cpp:53:18:53:21 | (int)... | AST only | +| test.cpp:88:12:88:12 | 0 | test.cpp:56:39:56:42 | (int)... | AST only | +| test.cpp:88:12:88:12 | 0 | test.cpp:59:17:59:20 | (int)... | AST only | +| test.cpp:88:12:88:12 | (void *)... | test.cpp:88:12:88:12 | (void *)... | AST only | +| test.cpp:92:11:92:16 | ... = ... | test.cpp:92:15:92:16 | 10 | IR only | +| test.cpp:92:11:92:16 | ... = ... | test.cpp:93:10:93:10 | x | IR only | +| test.cpp:92:15:92:16 | 10 | test.cpp:92:11:92:16 | ... = ... | IR only | +| test.cpp:92:15:92:16 | 10 | test.cpp:93:10:93:10 | x | IR only | +| test.cpp:93:10:93:10 | x | test.cpp:92:11:92:16 | ... = ... | IR only | +| test.cpp:93:10:93:10 | x | test.cpp:92:15:92:16 | 10 | IR only | +| test.cpp:105:11:105:12 | (Base *)... | test.cpp:105:11:105:12 | (Base *)... | AST only | +| test.cpp:105:11:105:12 | (Base *)... | test.cpp:106:14:106:35 | static_cast... | AST only | +| test.cpp:105:11:105:12 | (Base *)... | test.cpp:107:11:107:12 | pb | AST only | +| test.cpp:105:11:105:12 | pd | test.cpp:107:11:107:12 | pb | IR only | +| test.cpp:106:14:106:35 | static_cast... | test.cpp:105:11:105:12 | (Base *)... | AST only | +| test.cpp:106:14:106:35 | static_cast... | test.cpp:106:14:106:35 | static_cast... | AST only | +| test.cpp:106:14:106:35 | static_cast... | test.cpp:107:11:107:12 | pb | AST only | +| test.cpp:106:33:106:34 | pd | test.cpp:107:11:107:12 | pb | IR only | +| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | (Base *)... | AST only | +| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | pd | IR only | +| test.cpp:107:11:107:12 | pb | test.cpp:106:14:106:35 | static_cast... | AST only | +| test.cpp:107:11:107:12 | pb | test.cpp:106:33:106:34 | pd | IR only | +| test.cpp:113:3:113:5 | a | test.cpp:115:3:115:5 | a | IR only | +| test.cpp:115:3:115:5 | a | test.cpp:113:3:113:5 | a | IR only | +| test.cpp:125:15:125:15 | x | test.cpp:128:7:128:7 | x | AST only | +| test.cpp:126:15:126:15 | x | test.cpp:128:7:128:7 | x | AST only | +| test.cpp:128:3:128:11 | ... = ... | test.cpp:128:3:128:11 | ... = ... | AST only | +| test.cpp:128:7:128:7 | x | test.cpp:125:15:125:15 | x | AST only | +| test.cpp:128:7:128:7 | x | test.cpp:126:15:126:15 | x | AST only | +| test.cpp:128:11:128:11 | n | test.cpp:129:15:129:15 | x | IR only | +| test.cpp:129:15:129:15 | x | test.cpp:128:11:128:11 | n | IR only | +| test.cpp:136:21:136:21 | x | test.cpp:137:21:137:21 | x | AST only | +| test.cpp:136:21:136:21 | x | test.cpp:139:13:139:13 | x | AST only | +| test.cpp:137:21:137:21 | x | test.cpp:136:21:136:21 | x | AST only | +| test.cpp:137:21:137:21 | x | test.cpp:139:13:139:13 | x | AST only | +| test.cpp:139:3:139:24 | ... = ... | test.cpp:139:3:139:24 | ... = ... | AST only | +| test.cpp:139:13:139:13 | x | test.cpp:136:21:136:21 | x | AST only | +| test.cpp:139:13:139:13 | x | test.cpp:137:21:137:21 | x | AST only | +| test.cpp:144:15:144:15 | x | test.cpp:149:15:149:15 | x | IR only | +| test.cpp:145:15:145:15 | y | test.cpp:147:7:147:7 | y | AST only | +| test.cpp:147:3:147:18 | ... = ... | test.cpp:147:3:147:18 | ... = ... | AST only | +| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only | +| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only | +| test.cpp:153:21:153:21 | x | test.cpp:154:21:154:21 | x | AST only | +| test.cpp:154:21:154:21 | x | test.cpp:153:21:153:21 | x | AST only | +| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only | From 59a19679ea3bedb6878999e997d8bc05e1b512ac Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 19 Feb 2020 11:06:00 +0100 Subject: [PATCH 051/134] C++/C#: Sync identical files after merge --- .../gvn/internal/ValueNumberingInternal.qll | 2 +- .../gvn/internal/ValueNumberingInternal.qll | 2 +- .../gvn/internal/ValueNumberingInternal.qll | 2 +- .../gvn/internal/ValueNumberingInternal.qll | 76 +++++++++++-------- .../gvn/internal/ValueNumberingInternal.qll | 76 +++++++++++-------- 5 files changed, 91 insertions(+), 67 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll index 367436bceae..169b0ef7ccf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF instr.getEnclosingIRFunction() = irFunc } -predicate constantValueNumber( +private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { instr.getEnclosingIRFunction() = irFunc and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 367436bceae..169b0ef7ccf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF instr.getEnclosingIRFunction() = irFunc } -predicate constantValueNumber( +private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { instr.getEnclosingIRFunction() = irFunc and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 367436bceae..169b0ef7ccf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF instr.getEnclosingIRFunction() = irFunc } -predicate constantValueNumber( +private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { instr.getEnclosingIRFunction() = irFunc and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 252bb75a9fa..169b0ef7ccf 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -18,19 +18,18 @@ newtype TValueNumber = fieldAddressValueNumber(_, irFunc, field, objectAddress) } or TBinaryValueNumber( - IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand, - TValueNumber rightOperand + IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand ) { - binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand) + binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand) } or TPointerArithmeticValueNumber( - IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand, + IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand ) { - pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand) + pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand) } or - TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) { - unaryValueNumber(_, irFunc, opcode, type, operand) + TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) { + unaryValueNumber(_, irFunc, opcode, operand) } or TInheritanceConversionValueNumber( IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, @@ -99,6 +98,19 @@ private predicate numberableInstruction(Instruction instr) { instr instanceof LoadTotalOverlapInstruction } +private predicate filteredNumberableInstruction(Instruction instr) { + // count rather than strictcount to handle missing AST elements + // separate instanceof and inline casts to avoid failed casts with a count of 0 + instr instanceof VariableAddressInstruction and + count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1 + or + instr instanceof ConstantInstruction and + count(instr.getResultIRType()) != 1 + or + instr instanceof FieldAddressInstruction and + count(instr.(FieldAddressInstruction).getField()) != 1 +} + private predicate variableAddressValueNumber( VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast ) { @@ -106,7 +118,8 @@ private predicate variableAddressValueNumber( // The underlying AST element is used as value-numbering key instead of the // `IRVariable` to work around a problem where a variable or expression with // multiple types gives rise to multiple `IRVariable`s. - instr.getIRVariable().getAST() = ast + instr.getIRVariable().getAST() = ast and + strictcount(instr.getIRVariable().getAST()) = 1 } private predicate initializeParameterValueNumber( @@ -127,6 +140,7 @@ private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { instr.getEnclosingIRFunction() = irFunc and + strictcount(instr.getResultIRType()) = 1 and instr.getResultIRType() = type and instr.getValue() = value } @@ -145,42 +159,40 @@ private predicate fieldAddressValueNumber( ) { instr.getEnclosingIRFunction() = irFunc and instr.getField() = field and + strictcount(instr.getField()) = 1 and tvalueNumber(instr.getObjectAddress()) = objectAddress } private predicate binaryValueNumber( - BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand, + BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and not instr instanceof PointerArithmeticInstruction and instr.getOpcode() = opcode and - instr.getResultIRType() = type and tvalueNumber(instr.getLeft()) = leftOperand and tvalueNumber(instr.getRight()) = rightOperand } private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, - int elementSize, TValueNumber leftOperand, TValueNumber rightOperand + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize, + TValueNumber leftOperand, TValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and instr.getOpcode() = opcode and - instr.getResultIRType() = type and instr.getElementSize() = elementSize and tvalueNumber(instr.getLeft()) = leftOperand and tvalueNumber(instr.getRight()) = rightOperand } private predicate unaryValueNumber( - UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand + UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand ) { instr.getEnclosingIRFunction() = irFunc and not instr instanceof InheritanceConversionInstruction and not instr instanceof CopyInstruction and not instr instanceof FieldAddressInstruction and instr.getOpcode() = opcode and - instr.getResultIRType() = type and tvalueNumber(instr.getUnary()) = operand } @@ -200,9 +212,9 @@ private predicate loadTotalOverlapValueNumber( TValueNumber operand ) { instr.getEnclosingIRFunction() = irFunc and - instr.getResultIRType() = type and tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and - tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand + tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and + instr.getResultIRType() = type } /** @@ -212,7 +224,11 @@ private predicate loadTotalOverlapValueNumber( private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { instr.getEnclosingIRFunction() = irFunc and not instr.getResultIRType() instanceof IRVoidType and - not numberableInstruction(instr) + ( + not numberableInstruction(instr) + or + filteredNumberableInstruction(instr) + ) } /** @@ -255,7 +271,7 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { initializeThisValueNumber(instr, irFunc) and result = TInitializeThisValueNumber(irFunc) or - exists(IRType type, string value | + exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) ) @@ -270,14 +286,14 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TFieldAddressValueNumber(irFunc, field, objectAddress) ) or - exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand | - binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and - result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand) + exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand | + binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and + result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand) ) or - exists(Opcode opcode, IRType type, TValueNumber operand | - unaryValueNumber(instr, irFunc, opcode, type, operand) and - result = TUnaryValueNumber(irFunc, opcode, type, operand) + exists(Opcode opcode, TValueNumber operand | + unaryValueNumber(instr, irFunc, opcode, operand) and + result = TUnaryValueNumber(irFunc, opcode, operand) ) or exists( @@ -287,14 +303,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) ) or - exists( - Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand, - TValueNumber rightOperand - | - pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, - rightOperand) and + exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand | + pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and result = - TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand) + TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand) ) or exists(IRType type, TValueNumber memOperand, TValueNumber operand | diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 252bb75a9fa..169b0ef7ccf 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -18,19 +18,18 @@ newtype TValueNumber = fieldAddressValueNumber(_, irFunc, field, objectAddress) } or TBinaryValueNumber( - IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand, - TValueNumber rightOperand + IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand ) { - binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand) + binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand) } or TPointerArithmeticValueNumber( - IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand, + IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand ) { - pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand) + pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand) } or - TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) { - unaryValueNumber(_, irFunc, opcode, type, operand) + TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) { + unaryValueNumber(_, irFunc, opcode, operand) } or TInheritanceConversionValueNumber( IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, @@ -99,6 +98,19 @@ private predicate numberableInstruction(Instruction instr) { instr instanceof LoadTotalOverlapInstruction } +private predicate filteredNumberableInstruction(Instruction instr) { + // count rather than strictcount to handle missing AST elements + // separate instanceof and inline casts to avoid failed casts with a count of 0 + instr instanceof VariableAddressInstruction and + count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1 + or + instr instanceof ConstantInstruction and + count(instr.getResultIRType()) != 1 + or + instr instanceof FieldAddressInstruction and + count(instr.(FieldAddressInstruction).getField()) != 1 +} + private predicate variableAddressValueNumber( VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast ) { @@ -106,7 +118,8 @@ private predicate variableAddressValueNumber( // The underlying AST element is used as value-numbering key instead of the // `IRVariable` to work around a problem where a variable or expression with // multiple types gives rise to multiple `IRVariable`s. - instr.getIRVariable().getAST() = ast + instr.getIRVariable().getAST() = ast and + strictcount(instr.getIRVariable().getAST()) = 1 } private predicate initializeParameterValueNumber( @@ -127,6 +140,7 @@ private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { instr.getEnclosingIRFunction() = irFunc and + strictcount(instr.getResultIRType()) = 1 and instr.getResultIRType() = type and instr.getValue() = value } @@ -145,42 +159,40 @@ private predicate fieldAddressValueNumber( ) { instr.getEnclosingIRFunction() = irFunc and instr.getField() = field and + strictcount(instr.getField()) = 1 and tvalueNumber(instr.getObjectAddress()) = objectAddress } private predicate binaryValueNumber( - BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand, + BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and not instr instanceof PointerArithmeticInstruction and instr.getOpcode() = opcode and - instr.getResultIRType() = type and tvalueNumber(instr.getLeft()) = leftOperand and tvalueNumber(instr.getRight()) = rightOperand } private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, - int elementSize, TValueNumber leftOperand, TValueNumber rightOperand + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize, + TValueNumber leftOperand, TValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and instr.getOpcode() = opcode and - instr.getResultIRType() = type and instr.getElementSize() = elementSize and tvalueNumber(instr.getLeft()) = leftOperand and tvalueNumber(instr.getRight()) = rightOperand } private predicate unaryValueNumber( - UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand + UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand ) { instr.getEnclosingIRFunction() = irFunc and not instr instanceof InheritanceConversionInstruction and not instr instanceof CopyInstruction and not instr instanceof FieldAddressInstruction and instr.getOpcode() = opcode and - instr.getResultIRType() = type and tvalueNumber(instr.getUnary()) = operand } @@ -200,9 +212,9 @@ private predicate loadTotalOverlapValueNumber( TValueNumber operand ) { instr.getEnclosingIRFunction() = irFunc and - instr.getResultIRType() = type and tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and - tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand + tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and + instr.getResultIRType() = type } /** @@ -212,7 +224,11 @@ private predicate loadTotalOverlapValueNumber( private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { instr.getEnclosingIRFunction() = irFunc and not instr.getResultIRType() instanceof IRVoidType and - not numberableInstruction(instr) + ( + not numberableInstruction(instr) + or + filteredNumberableInstruction(instr) + ) } /** @@ -255,7 +271,7 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { initializeThisValueNumber(instr, irFunc) and result = TInitializeThisValueNumber(irFunc) or - exists(IRType type, string value | + exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) ) @@ -270,14 +286,14 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TFieldAddressValueNumber(irFunc, field, objectAddress) ) or - exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand | - binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and - result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand) + exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand | + binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and + result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand) ) or - exists(Opcode opcode, IRType type, TValueNumber operand | - unaryValueNumber(instr, irFunc, opcode, type, operand) and - result = TUnaryValueNumber(irFunc, opcode, type, operand) + exists(Opcode opcode, TValueNumber operand | + unaryValueNumber(instr, irFunc, opcode, operand) and + result = TUnaryValueNumber(irFunc, opcode, operand) ) or exists( @@ -287,14 +303,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) ) or - exists( - Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand, - TValueNumber rightOperand - | - pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, - rightOperand) and + exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand | + pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and result = - TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand) + TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand) ) or exists(IRType type, TValueNumber memOperand, TValueNumber operand | From df29143b7e31803e1e2a2c369ce5390b8c5c3134 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 19 Feb 2020 13:02:24 +0000 Subject: [PATCH 052/134] C++: Fix a test that should be working on the AST dataflow. --- .../dataflow/security-taint/tainted.expected | 22 ++++++++++++++----- .../dataflow/security-taint/tainted.ql | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected index 114c213ff54..7359b068d8e 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected @@ -15,27 +15,39 @@ | test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | | | test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | | | test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | envStrGlobal | | test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | envStrGlobal | | test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | | | test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | | | test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | envStrGlobal | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:28:50:40 | & ... | envStrGlobal | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | envStrGlobal | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | | | test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | envStrGlobal | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | envStrGlobal | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | envStrGlobal | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | envStrGlobal | | test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | | | test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | | | test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | | | test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | | | test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | | | test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:67:7:67:13 | copying | | | test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | | | test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | | | test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | | | test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | | | test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | | | test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | | | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | | | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | | diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted.ql b/cpp/ql/test/library-tests/dataflow/security-taint/tainted.ql index 64a724c4cab..4caea41850e 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted.ql +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted.ql @@ -1,4 +1,4 @@ -import semmle.code.cpp.security.TaintTracking +import semmle.code.cpp.security.TaintTrackingImpl from Expr source, Element tainted, string globalVar where From c6016bb08cd189af76e851b3fe60ebd01786c73b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 19 Feb 2020 14:47:39 +0100 Subject: [PATCH 053/134] Java/C++/C#: Improve join-order in pathStep predicate --- .../cpp/dataflow/internal/DataFlowImpl.qll | 26 ++++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl2.qll | 26 ++++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl3.qll | 26 ++++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl4.qll | 26 ++++++++++++++----- .../dataflow/internal/DataFlowImplLocal.qll | 26 ++++++++++++++----- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 26 ++++++++++++++----- .../ir/dataflow/internal/DataFlowImpl2.qll | 26 ++++++++++++++----- .../ir/dataflow/internal/DataFlowImpl3.qll | 26 ++++++++++++++----- .../ir/dataflow/internal/DataFlowImpl4.qll | 26 ++++++++++++++----- .../csharp/dataflow/internal/DataFlowImpl.qll | 26 ++++++++++++++----- .../dataflow/internal/DataFlowImpl2.qll | 26 ++++++++++++++----- .../dataflow/internal/DataFlowImpl3.qll | 26 ++++++++++++++----- .../dataflow/internal/DataFlowImpl4.qll | 26 ++++++++++++++----- .../dataflow/internal/DataFlowImpl5.qll | 26 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl.qll | 26 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl2.qll | 26 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl3.qll | 26 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl4.qll | 26 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl5.qll | 26 ++++++++++++++----- 19 files changed, 361 insertions(+), 133 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 86d44e4fcce..9bf0423ca7d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -2257,13 +2257,11 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | - midnode = mid.getNode() and - conf = mid.getConfiguration() and - cc = mid.getCallContext() and - sc = mid.getSummaryCtx() and - localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and - ap0 = mid.getAp() + exists( + AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + | + pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and + localCC = getLocalCallContext(cc, enclosing) | localFlowBigStep(midnode, node, true, conf, localCC) and ap = ap0 @@ -2297,6 +2295,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } +pragma[nomagic] +private predicate pathIntoLocalStep( + PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, + Configuration conf +) { + midnode = mid.getNode() and + cc = mid.getCallContext() and + conf = mid.getConfiguration() and + localFlowBigStep(midnode, _, _, conf, _) and + enclosing = midnode.getEnclosingCallable() and + sc = mid.getSummaryCtx() and + ap0 = mid.getAp() +} + pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { readDirect(node1, f, node2) and From 3e49e1212678ce1cdda330c366ea14aedf69ffa2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 19 Feb 2020 13:12:46 +0000 Subject: [PATCH 054/134] C++ Repair GlobalValueNumbering (AST) test. --- .../GlobalValueNumbering.expected | 82 +++++++++---------- .../GlobalValueNumbering.ql | 2 +- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.expected index 052ecf50921..d5d46ee0b72 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.expected @@ -1,42 +1,40 @@ -| test.cpp:5:3:5:3 | GVN | 5:c3-c3 6:c3-c3 | -| test.cpp:5:7:5:8 | GVN | 5:c7-c8 6:c7-c8 | -| test.cpp:5:7:5:13 | GVN | 5:c7-c13 6:c7-c13 7:c7-c7 | -| test.cpp:5:12:5:13 | GVN | 5:c12-c13 6:c12-c13 | -| test.cpp:16:3:16:3 | GVN | 16:c3-c3 17:c3-c3 | -| test.cpp:16:7:16:8 | GVN | 16:c7-c8 17:c7-c8 | -| test.cpp:16:7:16:13 | GVN | 16:c7-c13 17:c7-c13 | -| test.cpp:16:7:16:24 | GVN | 16:c7-c24 17:c7-c24 18:c7-c7 | -| test.cpp:16:12:16:13 | GVN | 16:c12-c13 17:c12-c13 | -| test.cpp:16:17:16:24 | GVN | 16:c17-c24 17:c17-c24 | -| test.cpp:29:3:29:3 | GVN | 29:c3-c3 31:c3-c3 | -| test.cpp:29:7:29:8 | GVN | 29:c7-c8 31:c7-c8 | -| test.cpp:29:7:29:13 | GVN | 29:c7-c13 31:c7-c13 | -| test.cpp:29:12:29:13 | GVN | 29:c12-c13 31:c12-c13 | -| test.cpp:31:7:31:24 | GVN | 31:c7-c24 32:c7-c7 | -| test.cpp:43:3:43:3 | GVN | 43:c3-c3 45:c3-c3 | -| test.cpp:43:7:43:8 | GVN | 43:c7-c8 45:c7-c8 | -| test.cpp:43:7:43:13 | GVN | 43:c7-c13 45:c7-c13 | -| test.cpp:43:7:43:24 | GVN | 43:c7-c24 45:c7-c24 46:c7-c7 | -| test.cpp:43:12:43:13 | GVN | 43:c12-c13 45:c12-c13 | -| test.cpp:43:17:43:24 | GVN | 43:c17-c24 45:c17-c24 | -| test.cpp:44:3:44:5 | GVN | 44:c3-c5 44:c4-c5 | -| test.cpp:53:10:53:13 | GVN | 53:c10-c13 56:c21-c24 | -| test.cpp:53:10:53:13 | GVN | 53:c10-c13 56:c21-c24 | -| test.cpp:53:11:53:13 | GVN | 53:c11-c13 56:c22-c24 | -| test.cpp:53:18:53:21 | GVN | 53:c18-c21 56:c39-c42 59:c17-c20 | -| test.cpp:56:14:56:16 | GVN | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 | -| test.cpp:62:5:62:10 | GVN | 62:c5-c10 65:c10-c15 | -| test.cpp:77:20:77:28 | GVN | 77:c20-c28 79:c7-c7 | -| test.cpp:79:11:79:14 | GVN | 79:c11-c14 79:c24-c27 | -| test.cpp:92:11:92:16 | GVN | 92:c11-c16 92:c15-c16 93:c10-c10 | -| test.cpp:105:11:105:12 | GVN | 105:c11-c12 106:c33-c34 | -| test.cpp:105:11:105:12 | GVN | 105:c11-c12 106:c33-c34 107:c11-c12 | -| test.cpp:105:15:105:15 | GVN | 105:c15-c15 107:c15-c15 109:c10-c10 | -| test.cpp:113:3:113:5 | GVN | 113:c3-c5 115:c3-c5 | -| test.cpp:125:11:125:12 | GVN | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 | -| test.cpp:125:15:125:15 | GVN | 125:c15-c15 126:c15-c15 | -| test.cpp:128:11:128:11 | GVN | 128:c11-c11 129:c15-c15 | -| test.cpp:136:11:136:18 | GVN | 136:c11-c18 137:c11-c18 139:c3-c10 | -| test.cpp:144:11:144:12 | GVN | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 | -| test.cpp:144:15:144:15 | GVN | 144:c15-c15 149:c15-c15 | -| test.cpp:153:11:153:18 | GVN | 153:c11-c18 154:c11-c18 156:c3-c10 | +| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 | +| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 | +| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 | +| test.cpp:5:12:5:13 | p1 | 5:c12-c13 6:c12-c13 | +| test.cpp:16:3:16:3 | x | 16:c3-c3 17:c3-c3 | +| test.cpp:16:7:16:8 | p0 | 16:c7-c8 17:c7-c8 | +| test.cpp:16:7:16:13 | ... + ... | 16:c7-c13 17:c7-c13 | +| test.cpp:16:7:16:24 | ... + ... | 16:c7-c24 17:c7-c24 18:c7-c7 | +| test.cpp:16:12:16:13 | p1 | 16:c12-c13 17:c12-c13 | +| test.cpp:16:17:16:24 | global01 | 16:c17-c24 17:c17-c24 | +| test.cpp:29:7:29:8 | p0 | 29:c7-c8 31:c7-c8 | +| test.cpp:29:7:29:13 | ... + ... | 29:c7-c13 31:c7-c13 | +| test.cpp:29:12:29:13 | p1 | 29:c12-c13 31:c12-c13 | +| test.cpp:31:7:31:24 | ... + ... | 31:c7-c24 32:c7-c7 | +| test.cpp:43:7:43:8 | p0 | 43:c7-c8 45:c7-c8 | +| test.cpp:43:7:43:13 | ... + ... | 43:c7-c13 45:c7-c13 | +| test.cpp:43:12:43:13 | p1 | 43:c12-c13 45:c12-c13 | +| test.cpp:44:9:44:9 | 0 | 44:c9-c9 51:c25-c25 53:c18-c21 56:c39-c42 59:c17-c20 88:c12-c12 | +| test.cpp:45:7:45:24 | ... + ... | 45:c7-c24 46:c7-c7 | +| test.cpp:53:10:53:13 | (int)... | 53:c10-c13 56:c21-c24 | +| test.cpp:53:10:53:13 | * ... | 53:c10-c13 56:c21-c24 | +| test.cpp:53:11:53:13 | str | 53:c11-c13 56:c22-c24 | +| test.cpp:53:18:53:21 | 0 | 53:c18-c21 56:c39-c42 59:c17-c20 | +| test.cpp:56:13:56:16 | (int)... | 56:c13-c16 56:c31-c34 59:c9-c12 | +| test.cpp:56:13:56:16 | * ... | 56:c13-c16 56:c31-c34 59:c9-c12 | +| test.cpp:56:14:56:16 | ptr | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 | +| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 | +| test.cpp:77:20:77:30 | (signed short)... | 77:c20-c30 79:c7-c7 | +| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 | +| test.cpp:105:11:105:12 | (Base *)... | 105:c11-c12 106:c14-c35 107:c11-c12 | +| test.cpp:105:11:105:12 | pd | 105:c11-c12 106:c33-c34 | +| test.cpp:105:15:105:15 | b | 105:c15-c15 107:c15-c15 109:c10-c10 | +| test.cpp:125:11:125:12 | pa | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 | +| test.cpp:125:15:125:15 | x | 125:c15-c15 126:c15-c15 128:c7-c7 | +| test.cpp:136:11:136:18 | global_a | 136:c11-c18 137:c11-c18 139:c3-c10 | +| test.cpp:136:21:136:21 | x | 136:c21-c21 137:c21-c21 139:c13-c13 | +| test.cpp:144:11:144:12 | pa | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 | +| test.cpp:145:15:145:15 | y | 145:c15-c15 147:c7-c7 | +| test.cpp:153:11:153:18 | global_a | 153:c11-c18 154:c11-c18 156:c3-c10 | +| test.cpp:153:21:153:21 | x | 153:c21-c21 154:c21-c21 | diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.ql b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.ql index 3807d5c36e0..84d0a7b3672 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.ql +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.ql @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl from GVN g where strictcount(g.getAnExpr()) > 1 From c014ca6ed79149dfce9938588d8e42fdc5c0ea31 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 19 Feb 2020 14:33:57 +0000 Subject: [PATCH 055/134] C++: Rename some tests for clarity / less emphasis on the AST. --- .../{GlobalValueNumbering.expected => ast_gvn.expected} | 0 .../GlobalValueNumbering/{GlobalValueNumbering.ql => ast_gvn.ql} | 0 .../{Uniqueness.expected => ast_uniqueness.expected} | 0 .../GlobalValueNumbering/{Uniqueness.ql => ast_uniqueness.ql} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/{GlobalValueNumbering.expected => ast_gvn.expected} (100%) rename cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/{GlobalValueNumbering.ql => ast_gvn.ql} (100%) rename cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/{Uniqueness.expected => ast_uniqueness.expected} (100%) rename cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/{Uniqueness.ql => ast_uniqueness.ql} (100%) diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.expected similarity index 100% rename from cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.expected rename to cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.expected diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.ql b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.ql similarity index 100% rename from cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/GlobalValueNumbering.ql rename to cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.ql diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.expected similarity index 100% rename from cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.expected rename to cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.expected diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.ql b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.ql similarity index 100% rename from cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/Uniqueness.ql rename to cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.ql From 5f7085937ee4856abb5bd83ab86f96978dd05733 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 14 Feb 2020 17:22:52 +0000 Subject: [PATCH 056/134] C++: Improve the SideEffect library QLDoc. --- .../src/semmle/code/cpp/models/interfaces/SideEffect.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index 905e79eb32b..3c2b15a09f8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -18,14 +18,18 @@ abstract class SideEffectFunction extends Function { /** * Holds if the function never reads from memory that was defined before entry to the function. * This memory could be from global variables, or from other memory that was reachable from a - * pointer that was passed into the function. + * pointer that was passed into the function. Input side-effects, and reads from memory that + * cannot be visible to the caller (for example a buffer inside an I/O library) are not modelled + * here. */ abstract predicate hasOnlySpecificReadSideEffects(); /** * Holds if the function never writes to memory that remains allocated after the function * returns. This memory could be from global variables, or from other memory that was reachable - * from a pointer that was passed into the function. + * from a pointer that was passed into the function. Output side-effects, and writes to memory + * that cannot be visible to the caller (for example a buffer inside an I/O library) are not + * modelled here. */ abstract predicate hasOnlySpecificWriteSideEffects(); From 22cba0f26e64d30737885f25f2f9fa074a2bd9b1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 14 Feb 2020 17:23:54 +0000 Subject: [PATCH 057/134] C++: Delete TODO. --- cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index 3c2b15a09f8..fda0f3869fe 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -47,7 +47,6 @@ abstract class SideEffectFunction extends Function { */ predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() } - // TODO: name? /** * Gets the index of the parameter that indicates the size of the buffer pointed to by the * parameter at index `i`. From 4e2a45cd3e81aaf4d32cc3fbb24a5a377c30c183 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 14 Feb 2020 17:28:24 +0000 Subject: [PATCH 058/134] C++: Correct SideEffectFunction model for PureStrFunction. --- cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index f25aed49d23..c831a8bf357 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -80,7 +80,7 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE override predicate parameterIsAlwaysReturned(int i) { none() } - override predicate hasOnlySpecificReadSideEffects() { none() } + override predicate hasOnlySpecificReadSideEffects() { any() } override predicate hasOnlySpecificWriteSideEffects() { any() } From 89bbb975f9d5c76ea4459a1f8a1c28c8dca1b8ad Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 19 Feb 2020 14:52:49 +0000 Subject: [PATCH 059/134] C++: Effects on tests. --- .../ir/ssa/aliased_ssa_ir.expected | 20 +++++++++---------- .../ir/ssa/aliased_ssa_ir_unsound.expected | 20 +++++++++---------- .../ir/ssa/unaliased_ssa_ir.expected | 20 +++++++++---------- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 20 +++++++++---------- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 5c12a3d2173..8f312e7f47f 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -886,27 +886,25 @@ ssa.cpp: # 199| r199_7(char *) = Load : &:r199_6, m198_11 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^CallReadSideEffect : ~m198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 -# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 -# 199| m199_13(int) = Store : &:r199_1, r199_9 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 +# 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : # 200| r200_3(char *) = Load : &:r200_2, m198_7 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^CallReadSideEffect : ~m198_4 -# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 -# 200| r200_8(glval) = VariableAddress[ret] : -# 200| r200_9(int) = Load : &:r200_8, m199_13 -# 200| r200_10(int) = Add : r200_9, r200_5 -# 200| m200_11(int) = Store : &:r200_8, r200_10 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 +# 200| r200_7(glval) = VariableAddress[ret] : +# 200| r200_8(int) = Load : &:r200_7, m199_12 +# 200| r200_9(int) = Add : r200_8, r200_5 +# 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : # 201| r201_3(int) = Load : &:r201_2, m198_15 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : -# 201| r201_6(int) = Load : &:r201_5, m200_11 +# 201| r201_6(int) = Load : &:r201_5, m200_10 # 201| r201_7(int) = Add : r201_6, r201_4 # 201| m201_8(int) = Store : &:r201_5, r201_7 # 202| r202_1(glval) = VariableAddress[#return] : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index 2a012447a68..c09c280bf9b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -883,27 +883,25 @@ ssa.cpp: # 199| r199_7(char *) = Load : &:r199_6, m198_11 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^CallReadSideEffect : ~m198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 -# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 -# 199| m199_13(int) = Store : &:r199_1, r199_9 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 +# 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : # 200| r200_3(char *) = Load : &:r200_2, m198_7 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^CallReadSideEffect : ~m198_4 -# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 -# 200| r200_8(glval) = VariableAddress[ret] : -# 200| r200_9(int) = Load : &:r200_8, m199_13 -# 200| r200_10(int) = Add : r200_9, r200_5 -# 200| m200_11(int) = Store : &:r200_8, r200_10 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 +# 200| r200_7(glval) = VariableAddress[ret] : +# 200| r200_8(int) = Load : &:r200_7, m199_12 +# 200| r200_9(int) = Add : r200_8, r200_5 +# 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : # 201| r201_3(int) = Load : &:r201_2, m198_15 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : -# 201| r201_6(int) = Load : &:r201_5, m200_11 +# 201| r201_6(int) = Load : &:r201_5, m200_10 # 201| r201_7(int) = Add : r201_6, r201_4 # 201| m201_8(int) = Store : &:r201_5, r201_7 # 202| r202_1(glval) = VariableAddress[#return] : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 4319cb86587..213f97589d6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -829,27 +829,25 @@ ssa.cpp: # 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 -# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 -# 199| m199_13(int) = Store : &:r199_1, r199_9 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 +# 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : # 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_4 -# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 -# 200| r200_8(glval) = VariableAddress[ret] : -# 200| r200_9(int) = Load : &:r200_8, m199_13 -# 200| r200_10(int) = Add : r200_9, r200_5 -# 200| m200_11(int) = Store : &:r200_8, r200_10 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 +# 200| r200_7(glval) = VariableAddress[ret] : +# 200| r200_8(int) = Load : &:r200_7, m199_12 +# 200| r200_9(int) = Add : r200_8, r200_5 +# 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : # 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : -# 201| r201_6(int) = Load : &:r201_5, m200_11 +# 201| r201_6(int) = Load : &:r201_5, m200_10 # 201| r201_7(int) = Add : r201_6, r201_4 # 201| m201_8(int) = Store : &:r201_5, r201_7 # 202| r202_1(glval) = VariableAddress[#return] : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index 4319cb86587..213f97589d6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -829,27 +829,25 @@ ssa.cpp: # 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 -# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 -# 199| m199_13(int) = Store : &:r199_1, r199_9 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 +# 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : # 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_4 -# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 -# 200| r200_8(glval) = VariableAddress[ret] : -# 200| r200_9(int) = Load : &:r200_8, m199_13 -# 200| r200_10(int) = Add : r200_9, r200_5 -# 200| m200_11(int) = Store : &:r200_8, r200_10 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 +# 200| r200_7(glval) = VariableAddress[ret] : +# 200| r200_8(int) = Load : &:r200_7, m199_12 +# 200| r200_9(int) = Add : r200_8, r200_5 +# 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : # 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : -# 201| r201_6(int) = Load : &:r201_5, m200_11 +# 201| r201_6(int) = Load : &:r201_5, m200_10 # 201| r201_7(int) = Add : r201_6, r201_4 # 201| m201_8(int) = Store : &:r201_5, r201_7 # 202| r202_1(glval) = VariableAddress[#return] : From 30913c9e7cd06e18931273060c05af870ce8c030 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 10 Feb 2020 14:54:14 +0000 Subject: [PATCH 060/134] docs: add info about using getAQlClass() (cherry picked from commit 3fb3b9b54ab742226ba07585c7e778b7bce92df9) --- .../writing-queries/debugging-queries.rst | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/language/learn-ql/writing-queries/debugging-queries.rst b/docs/language/learn-ql/writing-queries/debugging-queries.rst index 68bb1bae9b7..b0b03321354 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -62,6 +62,28 @@ is preferred over:: From the type context, the query optimizer deduces that some parts of the program are redundant and removes them, or *specializes* them. +Determine the most specific types of a variable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are unfamiliar with the library used in a query, you can use CodeQL to determine what types an entity has. There is a predicate called ``getAQlClass()``, which returns the most specific QL types of the entity that it is called on. + +For example, if you were working with a Java database, you might use ``getAQlClass()`` on every ``Expr`` in a callable called ``c``: + +.. code-block:: ql + + import java + + from Expr e, Callable c + where + c.getDeclaringType().hasQualifiedName("my.namespace.name", "MyClass") + and c.getName() = "c" + and e.getEnclosingCallable() = c + select e, e.getAQlClass() + +The result of this query is a list of the most specific types of every ``Expr`` in that function. You will see multiple results for expressions that are represented by more than one type, so it will likely return a very large table of results. + +Use ``getAQlClass()`` as a debugging tool, but don't include it in the final version of your query, as it slows down performance. + Avoid complex recursion ~~~~~~~~~~~~~~~~~~~~~~~ From afbb70af4748b0292a7dddca1e4140828c446d80 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 10 Feb 2020 14:57:03 +0000 Subject: [PATCH 061/134] docs: remove advanced ql topic about determining specific types (cherry picked from commit 3d90f6fe7147bad0106c0b6fdb3568a7a614bc36) --- .../learn-ql/advanced/advanced-ql.rst | 1 - .../determining-specific-types-variables.rst | 28 ------------------- 2 files changed, 29 deletions(-) delete mode 100644 docs/language/learn-ql/advanced/determining-specific-types-variables.rst diff --git a/docs/language/learn-ql/advanced/advanced-ql.rst b/docs/language/learn-ql/advanced/advanced-ql.rst index 051d649cf42..1e3ae338075 100644 --- a/docs/language/learn-ql/advanced/advanced-ql.rst +++ b/docs/language/learn-ql/advanced/advanced-ql.rst @@ -11,5 +11,4 @@ Advanced QL Topics on advanced uses of QL. These topics assume that you are familiar with QL and the basics of query writing. - :doc:`Choosing appropriate ways to constrain types ` -- :doc:`Determining the most specific types of a variable ` - :doc:`Monotonic aggregates in QL ` diff --git a/docs/language/learn-ql/advanced/determining-specific-types-variables.rst b/docs/language/learn-ql/advanced/determining-specific-types-variables.rst deleted file mode 100644 index 7deadde39c9..00000000000 --- a/docs/language/learn-ql/advanced/determining-specific-types-variables.rst +++ /dev/null @@ -1,28 +0,0 @@ -Determining the most specific types of a variable -================================================= - -It is sometimes useful to be able to determine what types an entity has -- especially when you are unfamiliar with the library used by a query. To help with this, there is a predicate called ``getAQlClass()``, which returns the most specific QL types of the entity that it is called on. - -This can be useful when you are not sure of the most precise class of a value. Discovering a more precise class can allow you to cast to it and use predicates that are not available on the more general class. - -Example -------- - -If you were working with a Java database, you might use ``getAQlClass()`` on every ``Expr`` in a callable called ``c``: - -**Java example** - -.. code-block:: ql - - import java - - from Expr e, Callable c - where - c.getDeclaringType().hasQualifiedName("my.namespace.name", "MyClass") - and c.getName() = "c" - and e.getEnclosingCallable() = c - select e, e.getAQlClass() - -The result of this query is a list of the most specific types of every ``Expr`` in that function. You will see multiple results for some expressions because that expression is represented by more than one type. - -For example, ``StringLiteral``\ s like ``"Hello"`` in Java belong to both the ``StringLiteral`` class (a specialization of the ``Literal`` class) and the ``CompileTimeConstantExpr`` class. So any instances of ``StringLiteral``\ s in the results will produce more than one result, one for each of the classes to which they belong. From 1f84722d2f4ff97bd4d72b408a499d17bcc2a3e1 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 10 Feb 2020 15:06:48 +0000 Subject: [PATCH 062/134] docs: delete constraining-types.rst (cherry picked from commit 142106bc993e4f6eba77b4283e18431756806842) --- .../learn-ql/advanced/advanced-ql.rst | 1 - .../learn-ql/advanced/constraining-types.rst | 73 ------------------- 2 files changed, 74 deletions(-) delete mode 100644 docs/language/learn-ql/advanced/constraining-types.rst diff --git a/docs/language/learn-ql/advanced/advanced-ql.rst b/docs/language/learn-ql/advanced/advanced-ql.rst index 1e3ae338075..d612c08b7cf 100644 --- a/docs/language/learn-ql/advanced/advanced-ql.rst +++ b/docs/language/learn-ql/advanced/advanced-ql.rst @@ -10,5 +10,4 @@ Advanced QL Topics on advanced uses of QL. These topics assume that you are familiar with QL and the basics of query writing. -- :doc:`Choosing appropriate ways to constrain types ` - :doc:`Monotonic aggregates in QL ` diff --git a/docs/language/learn-ql/advanced/constraining-types.rst b/docs/language/learn-ql/advanced/constraining-types.rst deleted file mode 100644 index 3a8d2e76637..00000000000 --- a/docs/language/learn-ql/advanced/constraining-types.rst +++ /dev/null @@ -1,73 +0,0 @@ -Constraining types -================== - -Type constraint methods ------------------------ - -.. pull-quote:: - - Note - - The examples below use the CodeQL library for Java. All libraries support using these methods to constrain variables, the only difference is in the names of the classes used. - -There are several ways of imposing type constraints on variables: - -- Use an ``instanceof`` test, for example: - - .. code-block:: ql - - import java - - from Type t - where t instanceof Class - select t - -- Use a cast, for example: - - .. code-block:: ql - - import java - - from Type t - where t.(Class).getASupertype().hasName("List") - select t - -- Set the variable equal to another variable with the required type using exists, for example: - - .. code-block:: ql - - import java - - from Type t - where exists(Class c | - c = t - and c.getASupertype().hasName("List") - ) - select t - -- Pass the variable to a predicate that expects a variable of the required type, for example: - - .. code-block:: ql - - import java - - predicate derivedFromList(Class c) { - c.getASupertype().hasName("List") - } - - from Type t - where derivedFromList(t) - select t - -All of these methods constrain the variable ``t`` to have values of type ``Class``. - -Choosing between the methods ----------------------------- - -These methods have advantages and disadvantages depending on the extent to which you need to work with the variable as the new type: - -- ``instanceof`` only checks that the variable has the required type. -- A cast gives you one, and only one, access to the variable as the new type. -- Creating a new variable with ``exists`` or a predicate parameter allows repeated access to the variable as the new type. - - - Note that due to the ability to overload predicates in a class, predicates that belong to a class must be supplied with arguments of the exact type they specify, and so this technique will not work in that situation. From 2bc5d11610b756b7a19b2948014e542a9ee1e251 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 19 Feb 2020 16:20:09 +0000 Subject: [PATCH 063/134] docs: delete advanced-ql section --- .../learn-ql/advanced/advanced-ql.rst | 13 - .../advanced/monotonic-aggregates.rst | 237 ------------------ docs/language/learn-ql/index.rst | 5 +- 3 files changed, 2 insertions(+), 253 deletions(-) delete mode 100644 docs/language/learn-ql/advanced/advanced-ql.rst delete mode 100644 docs/language/learn-ql/advanced/monotonic-aggregates.rst diff --git a/docs/language/learn-ql/advanced/advanced-ql.rst b/docs/language/learn-ql/advanced/advanced-ql.rst deleted file mode 100644 index d612c08b7cf..00000000000 --- a/docs/language/learn-ql/advanced/advanced-ql.rst +++ /dev/null @@ -1,13 +0,0 @@ -Advanced QL -=========== - -.. toctree:: - :glob: - :hidden: - - ./* - - -Topics on advanced uses of QL. These topics assume that you are familiar with QL and the basics of query writing. - -- :doc:`Monotonic aggregates in QL ` diff --git a/docs/language/learn-ql/advanced/monotonic-aggregates.rst b/docs/language/learn-ql/advanced/monotonic-aggregates.rst deleted file mode 100644 index 161776dbcf6..00000000000 --- a/docs/language/learn-ql/advanced/monotonic-aggregates.rst +++ /dev/null @@ -1,237 +0,0 @@ -Monotonic aggregates in QL -========================== - -In addition to standard aggregates, QL also supports *monotonic* aggregates. These are a slightly different way of computing aggregates which have some advantages, notably the ability to be used recursively, which normal aggregates do not have. You can enable them in a scope by adding the \ ``language[monotonicAggregates]`` pragma on a predicate, class, or module. - -Syntax ------- - -A QL aggregate is written in the following way: - -.. code-block:: ql - - aggregate(Type t, ... | range | expression) - -Where ``range`` is a QL formula, and ``expression`` is a QL expression. For example, you might write: - -.. code-block:: ql - - sum(Employee e | managedByMe(e) | e.getSalary()) - -to add up the salaries of the employees you manage. - -An aggregate is a QL expression. This means it may be equated to a variable or passed as an argument to a method or predicate, just like other expressions. - -The aggregate functions that are available are: - -- ``count`` - counts the expression values -- ``strictcount`` - counts the expression values, but fails if the range ever fails -- ``sum`` - sums the expression values -- ``strictsum`` - sums the expression values, but fails if the range ever fails -- ``avg`` - averages the expression values -- ``max`` - takes the maximum of the expression values -- ``min`` - takes the minimum of the expression values -- ``rank`` - ranks the variable values by their expression value - -``strictcount``, ``strictsum`` and ``rank`` are a little unusual, and are discussed in more detail `below <#aggregate-variants>`__. - -Semantics ---------- - -For most usages, aggregates have very straightforward behavior. They can be thought of according to the following recipe: - - For every combination of values for the declared **variables**, for which the **range** holds, take one value of the **expression** and apply the **aggregation function** to the resulting values. - -How does this work? Let us take the simple example given above of calculating the sum of your employees' salaries. Suppose that your employees are Alice, Ben, and Charles, whose salaries are $30k, $40k, and $50k respectively. Then to calculate ``result``, we follow our recipe: - -+----------------------------------------------------------------+-------------------------------------+ -| For every combination of values for the declared **variables** | Alice, Ben, Charles, Denis, Edna... | -+================================================================+=====================================+ -| for which the **range** holds | Alice, Ben, Charles | -+----------------------------------------------------------------+-------------------------------------+ -| take one value of the \ **expression** | $50k, $30k, $50k | -+----------------------------------------------------------------+-------------------------------------+ -| and apply the **aggregation function** to the resulting values | sum($50k, $30k, $50k) = $130k | -+----------------------------------------------------------------+-------------------------------------+ - -Missing expression values -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Our recipe is simple enough when there is precisely one value of the expression for each value given by the range - but what happens if there is not? QL is a relational language, so this is quite possible. Consider the following QL code: - -.. code-block:: ql - - int totalProjectTime() { - result = sum(Employee e | managedByMe(e) | e.getAProject().getRunTime()) - } - -What happens when an employee does not have any projects? In this case when we follow our recipe, there will be **no** values available for the expression, and so we will fail to produce any results at all. Let us suppose that Charles has no projects, then our recipe goes as follows: - -+----------------------------------------------------------------+-------------------------------------+ -| For every combination of values for the declared **variables** | Alice, Ben, Charles, Denis, Edna... | -+================================================================+=====================================+ -| for which the **range** holds | Alice, Ben, Charles | -+----------------------------------------------------------------+-------------------------------------+ -| take one value of the \ **expression** | Project A, Project B, ```` | -+----------------------------------------------------------------+-------------------------------------+ -| and apply the **aggregation function** to the resulting values |   | -+----------------------------------------------------------------+-------------------------------------+ - -This is probably an error in defining the query. The writer probably intended something more like this: - -.. code-block:: ql - - int totalProjectTime() { - result = sum(Project p | exists(Employee e | managedByMe(e) | p = e.getAProject()) | p.getRunTime()) - } - -This will correctly ignore employees who have no projects, although it will still fail if some projects do not have a run time. - -This kind of failure can be benign, and it is crucial to the proper behavior of recursive aggregation. - -Multiple expression values -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Not only may QL expressions have no values, they may have multiple values. Consider the following example: - -.. code-block:: ql - - int getProjectCostEstimate(Employee e) { - result = sum(Project p | e.getAProject() = p | p.getAnEstimate()) - } - -Let us suppose that ``Project.getAnEstimate`` is populated by asking a selection of people for an estimate on the project cost. In this case, the expression will return **multiple** estimates (as is common for QL methods named ``getA*``). For our example, suppose that an employee owns Project C and Project F, and the estimates for Project C are ($20k, $30k) and for Project F there is only ($40k). Then, following our recipe: - -+----------------------------------------------------------------+------------------------------------------------------+ -| For every combination of values for the declared **variables** | Project A, Project B, Project C... | -+================================================================+======================================================+ -| for which the **range** holds | Project C, Project F | -+----------------------------------------------------------------+------------------------------------------------------+ -| take one value of the \ **expression** | ($20k, $40K) **or** ($30k, $40k) | -+----------------------------------------------------------------+------------------------------------------------------+ -| and apply the **aggregation function** to the resulting values | sum($20k, $40k) = $60k **or** sum($30k, $40k) = $70k | -+----------------------------------------------------------------+------------------------------------------------------+ - -So in this case we actually get **two** values for ``result``. Since there were two possibilities for ``getAnEstimate`` for Project C, we got a total of 2 (for Project C) x 1 (for Project F) = 2 combinations of estimates, each of which gives a different value when aggregated. If there were more estimates for Project F, or more projects, each with their own set of estimates, then we would get more output values for the aggregate - one for each possible assignment of estimates to projects. - -This means that ``getProjectCostEstimate`` gives us a spread of options, capturing the range of different possible values we might get depending on which estimates are correct. - -Thinking about possible assignments to the variables also provides a different perspective on the previous section. An aggregation can fail to produce a value if the expression has no values for one of the aggregated entities because then there are **no** possible assignments of expression values to aggregated entities. - -The multivalued aspect of monotonic aggregates is less commonly used because monotonic aggregates with multiple expression values will often produce a large number of results, reflecting the various possible expression values. This is rarely what is intended, and can be expensive to compute (min, max, and count are exceptions to this, and have linear performance in all cases). - -If you have an unintentionally multivalued expression, this can usually be resolved by moving the multivalued part to the range and binding it to a new aggregation variable. - -Recursion -~~~~~~~~~ - -Aggregates **may** be used recursively, but the recursive call may only appear in the expression, and not in the range. For example, we might define a predicate to calculate the distance of a node in a graph from the leaves as follows: - -.. code-block:: ql - - int depth(Node n) { - if not exists(n.getAChild()) - then result = 0 - else result = 1 + max(Node child | child = n.getAChild() | depth(child)) - } - -Here the recursive call is in the expression, which is legal. - -The recursive semantics for aggregates are the same as the recursive semantics for the rest of QL. If you understand how aggregates work in the non-recursive case then you should not find it difficult to use them recursively. However, it is worth seeing how the evaluation of a recursive aggregation proceeds. - -Consider the depth example we just saw with the following graph as input (arrows point from children to parents): - -|image0| - -Then the evaluation of the ``depth`` predicate proceeds as follows: - -+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **Stage** | **depth** | **Comments** | -+===========+============================================+==========================================================================================================================================================================+ -| 0 |   | We always begin with the empty set. | -+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 1 | ``(0, b), (0, d), (0, e)`` | The nodes with no children have depth 0. The recursive step for **a** and **c** fails to produce a value, since some of their children do not have values for ``depth``. | -+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2 | ``(0, b), (0, d), (0, e), (1, c)`` | The recursive step for **c** succeeds, since ``depth`` now has a value for all its children (**d** and **e**). The recursive step for **a** still fails. | -+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 3 | ``(0, b), (0, d), (0, e), (1, c), (2, a)`` | The recursive step for **a** succeeds, since ``depth`` now has a value for all its children (**b** and **c**). | -+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -Here we can see that at the intermediate stages it is very important for the aggregate to fail if some of the children lack a value - this prevents erroneous values being added. - -Aggregate variants ------------------- - -Strict aggregates -~~~~~~~~~~~~~~~~~ - -The aggregates ``strictsum`` and ``strictcount`` are known as "strict" aggregates. This means that if there are no possible assignments to the aggregation variables that satisfy the range, then the aggregate fails to produce any values, instead of defaulting to zero (which is the behavior of ``sum`` and ``count``). This is useful if you're only interested in cases where the range of the aggregate is valid. For example, the query: - -.. code-block:: ql - - from Employee e - select e, sum(Project p | e.getAProject() = p | p.costToDate()) - -produces zeros for employees who have no projects. This may just clutter up the results, whereas: - -.. code-block:: ql - - from Employee e - select e, strictsum(Project p | e.getAProject() = p | p.costToDate()) - -will only produce results for employees who actually have projects. - -Rank -~~~~ - -Rank is a slightly unusual aggregate. It takes the possible values of the expression and ranks them, returning both the value and the corresponding rank. This has some special syntax to assign the rank to a variable. For example, the query: - -.. code-block:: ql - - from int salary, int salaryRank - where salary = rank[salaryRank](Employee e | managedByMe(e) | e.getSalary()) - select salary, salaryRank - -assigns, for each person I manage, their salary to ``salary``, and the rank of their salary to ``salaryRank``. In our running example, the results would be: - -+------------+----------------+ -| ``salary`` | ``salaryRank`` | -+============+================+ -| $50k | 1 | -+------------+----------------+ -| $30k | 3 | -+------------+----------------+ - -Note that the ranking does not ignore duplicates. Since there are two employees (Alice and Charles) with salary $50k, the two $50k salaries "tie" for first place, and the $30k salary is ranked in third. - -If you wanted to rank the employees themselves by salary, you could write the following query: - -.. code-block:: ql - - from Employee employee, int salaryRank - where employee.salary() = rank[salaryRank](Employee e | managedByMe(e) | e.salary()) - select employee, salaryRank order by salaryRank desc - -Abbreviated aggregates -~~~~~~~~~~~~~~~~~~~~~~ - -As we've described them so far, aggregates have three parts: a set of variable declarations, a range, and an expression. However, often it's unnecessarily verbose to write all three, when the intention is clear from context. QL allows you to abbreviate your aggregates in a number of ways. - -+---------------------------------------------+---------------------------------------------------+--------------------------------------------------------+------------------------------------------------------------+ -| Abbreviated form | Equivalent full form | Example | Result | -+=============================================+===================================================+========================================================+============================================================+ -| ``aggregate(expression)`` | ``aggregate(Type var | expression = var | var)`` | ``avg(e.getAProject().getRunTime())`` | The average run time of the projects belonging to ``e``. | -+---------------------------------------------+---------------------------------------------------+--------------------------------------------------------+------------------------------------------------------------+ -| ``aggregate(Type var, ... | | expression)`` | ``aggregate(Type var, ... | any() | expression)`` | ``min(Employee e | | e.getSalary())`` | The lowest salary of **any** employee. | -+---------------------------------------------+---------------------------------------------------+--------------------------------------------------------+------------------------------------------------------------+ -| ``aggregate(Type var)`` | ``aggregate(Type var | any () | var)`` | ``count(Employee e)`` | The total number of employees. | -+---------------------------------------------+---------------------------------------------------+--------------------------------------------------------+------------------------------------------------------------+ -| ``aggregate(Type var | range)`` | ``aggregate(Type var | range | var)`` | ``count(Employee e | managedByMe(e))`` | The number of employees managed by you. | -+---------------------------------------------+---------------------------------------------------+--------------------------------------------------------+------------------------------------------------------------+ -| ``count(Type var, ... | range)`` | ``count(Type var, ... | range | 1)`` | ``count(Employee e1, Employee e2 | e1.worksWith(e2))`` | The number of pairs of employees who work with each other. | -+---------------------------------------------+---------------------------------------------------+--------------------------------------------------------+------------------------------------------------------------+ - -These abbreviations are valid for any aggregate, except for the last, which is only valid for ``count``. - -.. |image0| image:: ../../images/monotonic-aggregates-graph.png - diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst index add850f5806..f25bf8bb644 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -73,8 +73,8 @@ For more information on using CodeQL to query code written in a specific languag javascript/ql-for-javascript python/ql-for-python -Advanced QL and technical information -************************************* +Technical information +********************* For more technical information see: @@ -82,7 +82,6 @@ For more technical information see: :maxdepth: 2 :includehidden: - advanced/advanced-ql technical-info Reference topics From 91166431d22be7211c9f8d754adadbab9099f4c2 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 19 Feb 2020 17:23:01 +0100 Subject: [PATCH 064/134] Java/C++/C#: s/Callable/DataFlowCallable/ --- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 7 ++++--- .../semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 7 ++++--- .../semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 7 ++++--- .../semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 7 ++++--- .../code/cpp/dataflow/internal/DataFlowImplLocal.qll | 7 ++++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 7 ++++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 7 ++++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 7 ++++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 7 ++++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 7 ++++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 7 ++++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 7 ++++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 7 ++++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 7 ++++--- .../semmle/code/java/dataflow/internal/DataFlowImpl.qll | 7 ++++--- .../semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 7 ++++--- .../semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 7 ++++--- .../semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 7 ++++--- .../semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 7 ++++--- 19 files changed, 76 insertions(+), 57 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 9bf0423ca7d..bf4ffd6270e 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -2258,7 +2258,8 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { exists( - AccessPath ap0, Node midnode, Configuration conf, Callable enclosing, LocalCallContext localCC + AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, + LocalCallContext localCC | pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and localCC = getLocalCallContext(cc, enclosing) @@ -2297,8 +2298,8 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pragma[nomagic] private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, Callable enclosing, SummaryCtx sc, AccessPath ap0, - Configuration conf + PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, + AccessPath ap0, Configuration conf ) { midnode = mid.getNode() and cc = mid.getCallContext() and From 479770dc0701f2b67b12e71d2321ec352586783b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 19 Feb 2020 15:29:02 +0000 Subject: [PATCH 065/134] JS: Recognize class members in more cases --- javascript/ql/src/semmle/javascript/dataflow/Nodes.qll | 8 ++++++++ .../test/library-tests/ClassNode/InstanceMember.expected | 2 ++ .../test/library-tests/ClassNode/InstanceMethod.expected | 2 ++ javascript/ql/test/library-tests/ClassNode/fields.ts | 3 +++ .../library-tests/ClassNode/getAReceiverNode.expected | 2 ++ javascript/ql/test/library-tests/ClassNode/tst2.js | 6 ++++++ 6 files changed, 23 insertions(+) create mode 100644 javascript/ql/test/library-tests/ClassNode/fields.ts diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index 98574813b92..e4d80cb53cd 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -1036,6 +1036,9 @@ module ClassNode { kind = MemberKind::of(method) and result = method.getBody().flow() ) + or + kind = MemberKind::method() and + result = getConstructor().getReceiver().getAPropertySource(name) } override FunctionNode getAnInstanceMember(MemberKind kind) { @@ -1045,6 +1048,9 @@ module ClassNode { kind = MemberKind::of(method) and result = method.getBody().flow() ) + or + kind = MemberKind::method() and + result = getConstructor().getReceiver().getAPropertySource() } override FunctionNode getStaticMethod(string name) { @@ -1063,6 +1069,8 @@ module ClassNode { method.isStatic() and result = method.getBody().flow() ) + or + result = getAPropertySource() } override DataFlow::Node getASuperClassNode() { result = astNode.getSuperClass().flow() } diff --git a/javascript/ql/test/library-tests/ClassNode/InstanceMember.expected b/javascript/ql/test/library-tests/ClassNode/InstanceMember.expected index 1566c4ff9c2..a6faded04a4 100644 --- a/javascript/ql/test/library-tests/ClassNode/InstanceMember.expected +++ b/javascript/ql/test/library-tests/ClassNode/InstanceMember.expected @@ -1,6 +1,8 @@ +| fields.ts:2:16:2:32 | (x: string) => {} | Foo.m | method | | namespace.js:5:32:5:44 | function() {} | Baz.method | method | | tst2.js:6:9:9:3 | () {\\n ... .x;\\n } | C.method | method | | tst2.js:11:13:13:3 | () {\\n ... .x;\\n } | C.getter | getter | +| tst2.js:18:14:18:22 | (x) => {} | D.f | method | | tst.js:4:17:4:21 | () {} | A.instanceMethod | method | | tst.js:7:6:7:10 | () {} | A.bar | method | | tst.js:9:10:9:14 | () {} | A.baz | getter | diff --git a/javascript/ql/test/library-tests/ClassNode/InstanceMethod.expected b/javascript/ql/test/library-tests/ClassNode/InstanceMethod.expected index d0406361e6b..c5b94a35a3c 100644 --- a/javascript/ql/test/library-tests/ClassNode/InstanceMethod.expected +++ b/javascript/ql/test/library-tests/ClassNode/InstanceMethod.expected @@ -1,5 +1,7 @@ +| fields.ts:2:16:2:32 | (x: string) => {} | Foo.m | | namespace.js:5:32:5:44 | function() {} | Baz.method | | tst2.js:6:9:9:3 | () {\\n ... .x;\\n } | C.method | +| tst2.js:18:14:18:22 | (x) => {} | D.f | | tst.js:4:17:4:21 | () {} | A.instanceMethod | | tst.js:7:6:7:10 | () {} | A.bar | | tst.js:17:19:17:31 | function() {} | B.foo | diff --git a/javascript/ql/test/library-tests/ClassNode/fields.ts b/javascript/ql/test/library-tests/ClassNode/fields.ts new file mode 100644 index 00000000000..f288a47bb4d --- /dev/null +++ b/javascript/ql/test/library-tests/ClassNode/fields.ts @@ -0,0 +1,3 @@ +class Foo { + public m = (x: string) => {}; +} diff --git a/javascript/ql/test/library-tests/ClassNode/getAReceiverNode.expected b/javascript/ql/test/library-tests/ClassNode/getAReceiverNode.expected index c17b1db03a4..f8f057d646f 100644 --- a/javascript/ql/test/library-tests/ClassNode/getAReceiverNode.expected +++ b/javascript/ql/test/library-tests/ClassNode/getAReceiverNode.expected @@ -1,8 +1,10 @@ +| fields.ts:1:1:3:1 | class F ... > {};\\n} | fields.ts:1:11:1:10 | this | | namespace.js:3:15:3:31 | function Baz() {} | namespace.js:3:15:3:14 | this | | namespace.js:3:15:3:31 | function Baz() {} | namespace.js:5:32:5:31 | this | | tst2.js:1:1:14:1 | class C ... ;\\n }\\n} | tst2.js:2:14:2:13 | this | | tst2.js:1:1:14:1 | class C ... ;\\n }\\n} | tst2.js:6:9:6:8 | this | | tst2.js:1:1:14:1 | class C ... ;\\n }\\n} | tst2.js:11:13:11:12 | this | +| tst2.js:16:1:20:1 | class D ... ;\\n }\\n} | tst2.js:17:14:17:13 | this | | tst.js:3:1:10:1 | class A ... () {}\\n} | tst.js:3:9:3:8 | this | | tst.js:3:1:10:1 | class A ... () {}\\n} | tst.js:4:17:4:16 | this | | tst.js:3:1:10:1 | class A ... () {}\\n} | tst.js:7:6:7:5 | this | diff --git a/javascript/ql/test/library-tests/ClassNode/tst2.js b/javascript/ql/test/library-tests/ClassNode/tst2.js index 88746d8fcd4..493fe027949 100644 --- a/javascript/ql/test/library-tests/ClassNode/tst2.js +++ b/javascript/ql/test/library-tests/ClassNode/tst2.js @@ -12,3 +12,9 @@ class C { return this.x; } } + +class D { + constructor() { + this.f = (x) => {}; + } +} From 8ea5739b7aa8d75560a9aa8ea28dd61edef27d0d Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 19 Feb 2020 14:32:49 -0800 Subject: [PATCH 066/134] C++: release note for DefaultTaintTracking --- change-notes/1.24/analysis-cpp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 77d27f425bc..133138fcfdd 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -46,3 +46,4 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. the following improvements: * The library now models data flow through `strdup` and similar functions. * The library now models data flow through formatting functions such as `sprintf`. +* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, removing false positives and adding true positives in many security queries. \ No newline at end of file From d151c2eeb78e33510111b0b02438eb150daadb4c Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 19 Feb 2020 14:39:36 -0800 Subject: [PATCH 067/134] C++: change note for IR-based GVN --- change-notes/1.24/analysis-cpp.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 133138fcfdd..600fe398fe0 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -46,4 +46,5 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. the following improvements: * The library now models data flow through `strdup` and similar functions. * The library now models data flow through formatting functions such as `sprintf`. -* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, removing false positives and adding true positives in many security queries. \ No newline at end of file +* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, removing false positives and adding true positives in many security queries. +* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new intermediate representation to provide a more precise analysis of heap allocated memory and pointers to stack variables. \ No newline at end of file From 5263222dc22d9011c050986a838237cf8f9b529f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 19 Feb 2020 15:57:19 -0700 Subject: [PATCH 068/134] "Fix" spelling --- cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index fda0f3869fe..a036c650caa 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -19,7 +19,7 @@ abstract class SideEffectFunction extends Function { * Holds if the function never reads from memory that was defined before entry to the function. * This memory could be from global variables, or from other memory that was reachable from a * pointer that was passed into the function. Input side-effects, and reads from memory that - * cannot be visible to the caller (for example a buffer inside an I/O library) are not modelled + * cannot be visible to the caller (for example a buffer inside an I/O library) are not modeled * here. */ abstract predicate hasOnlySpecificReadSideEffects(); From 4f1a23e248d026cfb71d73065e0f03d2212646cc Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 19 Feb 2020 15:57:31 -0700 Subject: [PATCH 069/134] "Fix" spelling --- cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index a036c650caa..3377db771a3 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -29,7 +29,7 @@ abstract class SideEffectFunction extends Function { * returns. This memory could be from global variables, or from other memory that was reachable * from a pointer that was passed into the function. Output side-effects, and writes to memory * that cannot be visible to the caller (for example a buffer inside an I/O library) are not - * modelled here. + * modeled here. */ abstract predicate hasOnlySpecificWriteSideEffects(); From 2d437efdfd0febae32cd9641ff9202624fd8e4d1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 20 Feb 2020 09:54:11 +0100 Subject: [PATCH 070/134] corrections on qldoc Co-Authored-By: Asger F --- .../ql/src/semmle/javascript/dataflow/Configuration.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 0cba3157ba9..28c7a62fb4f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1482,8 +1482,8 @@ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, Dat } /** - * A check of the form `if(x)`, which sanitizes `x` in its "else" branch. - * Can be added to a `isBarrier` in a configuration to add the sanitization. + * A guard node for a variable in a negative condition, such as `x` in `if(!x)`. + * Can be added to a `isBarrier` in a data-flow configuration to block flow through such checks. */ class VarAccessBarrier extends DataFlow::Node { VarAccessBarrier() { From 80962803b0fb1b4ab975a4d535be1bb14f65e2e1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 20 Feb 2020 10:09:32 +0100 Subject: [PATCH 071/134] update doc for VarAccessBarrier, and make the class private --- .../security/dataflow/TaintedPathCustomizations.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 62e42b1963a..69d86f2ac91 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -356,9 +356,9 @@ module TaintedPath { } /** - * A check of the form `if(x)`, which sanitizes `x` in its "else" branch. + * A guard node for a variable in a negative condition, such as `x` in `if(!x)`. */ - class VarAccessBarrier extends Sanitizer, DataFlow::VarAccessBarrier { } + private class VarAccessBarrier extends Sanitizer, DataFlow::VarAccessBarrier { } /** * A source of remote user input, considered as a flow source for From 6448acfa88e3f614cd25c420f6277de61c9949d0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 20 Feb 2020 10:53:17 +0000 Subject: [PATCH 072/134] TS: Depend on TypeScript 3.7.5 --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index fb6b9b987c9..f1f82f91f25 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "^3.7.2" + "typescript": "3.7.5" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 5116c7eb5c3..4562b05a011 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -225,9 +225,9 @@ tsutils@^2.12.1: dependencies: tslib "^1.8.1" -typescript@^3.7.2: - version "3.7.2" - resolved "typescript-3.7.2.tgz" +typescript@3.7.5: + version "3.7.5" + resolved "typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" wrappy@1: version "1.0.2" From 051d574ffd03d219992b812baaf800edfa5e17ec Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 20 Feb 2020 15:31:44 +0100 Subject: [PATCH 073/134] C++: Add switch testcases demonstrating incorrect IR --- .../library-tests/ir/ir/PrintAST.expected | 233 ++++++++++++++++++ cpp/ql/test/library-tests/ir/ir/ir.cpp | 49 ++++ .../test/library-tests/ir/ir/raw_ir.expected | 167 +++++++++++++ 3 files changed, 449 insertions(+) diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index 343ffc27db5..c2014db4cf8 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -8070,6 +8070,239 @@ ir.cpp: # 1170| Type = [ArrayType] const char[4] # 1170| Value = [StringLiteral] "foo" # 1170| ValueCategory = lvalue +# 1173| [TopLevelFunction] void switch1Case(int) +# 1173| params: +# 1173| 0: [Parameter] x +# 1173| Type = [IntType] int +# 1173| body: [Block] { ... } +# 1174| 0: [DeclStmt] declaration +# 1174| 0: [VariableDeclarationEntry] definition of y +# 1174| Type = [IntType] int +# 1174| init: [Initializer] initializer for y +# 1174| expr: [Literal] 0 +# 1174| Type = [IntType] int +# 1174| Value = [Literal] 0 +# 1174| ValueCategory = prvalue +# 1175| 1: [SwitchStmt] switch (...) ... +# 1175| 0: [VariableAccess] x +# 1175| Type = [IntType] int +# 1175| ValueCategory = prvalue(load) +# 1175| 1: [Block] { ... } +# 1176| 0: [SwitchCase] case ...: +# 1176| 0: [Literal] 1 +# 1176| Type = [IntType] int +# 1176| Value = [Literal] 1 +# 1176| ValueCategory = prvalue +# 1177| 1: [ExprStmt] ExprStmt +# 1177| 0: [AssignExpr] ... = ... +# 1177| Type = [IntType] int +# 1177| ValueCategory = lvalue +# 1177| 0: [VariableAccess] y +# 1177| Type = [IntType] int +# 1177| ValueCategory = lvalue +# 1177| 1: [Literal] 2 +# 1177| Type = [IntType] int +# 1177| Value = [Literal] 2 +# 1177| ValueCategory = prvalue +# 1179| 2: [DeclStmt] declaration +# 1179| 0: [VariableDeclarationEntry] definition of z +# 1179| Type = [IntType] int +# 1179| init: [Initializer] initializer for z +# 1179| expr: [VariableAccess] y +# 1179| Type = [IntType] int +# 1179| ValueCategory = prvalue(load) +# 1180| 3: [ReturnStmt] return ... +# 1182| [TopLevelFunction] void switch2Case_fallthrough(int) +# 1182| params: +# 1182| 0: [Parameter] x +# 1182| Type = [IntType] int +# 1182| body: [Block] { ... } +# 1183| 0: [DeclStmt] declaration +# 1183| 0: [VariableDeclarationEntry] definition of y +# 1183| Type = [IntType] int +# 1183| init: [Initializer] initializer for y +# 1183| expr: [Literal] 0 +# 1183| Type = [IntType] int +# 1183| Value = [Literal] 0 +# 1183| ValueCategory = prvalue +# 1184| 1: [SwitchStmt] switch (...) ... +# 1184| 0: [VariableAccess] x +# 1184| Type = [IntType] int +# 1184| ValueCategory = prvalue(load) +# 1184| 1: [Block] { ... } +# 1185| 0: [SwitchCase] case ...: +# 1185| 0: [Literal] 1 +# 1185| Type = [IntType] int +# 1185| Value = [Literal] 1 +# 1185| ValueCategory = prvalue +# 1186| 1: [ExprStmt] ExprStmt +# 1186| 0: [AssignExpr] ... = ... +# 1186| Type = [IntType] int +# 1186| ValueCategory = lvalue +# 1186| 0: [VariableAccess] y +# 1186| Type = [IntType] int +# 1186| ValueCategory = lvalue +# 1186| 1: [Literal] 2 +# 1186| Type = [IntType] int +# 1186| Value = [Literal] 2 +# 1186| ValueCategory = prvalue +# 1187| 2: [SwitchCase] case ...: +# 1187| 0: [Literal] 2 +# 1187| Type = [IntType] int +# 1187| Value = [Literal] 2 +# 1187| ValueCategory = prvalue +# 1188| 3: [ExprStmt] ExprStmt +# 1188| 0: [AssignExpr] ... = ... +# 1188| Type = [IntType] int +# 1188| ValueCategory = lvalue +# 1188| 0: [VariableAccess] y +# 1188| Type = [IntType] int +# 1188| ValueCategory = lvalue +# 1188| 1: [Literal] 3 +# 1188| Type = [IntType] int +# 1188| Value = [Literal] 3 +# 1188| ValueCategory = prvalue +# 1190| 2: [DeclStmt] declaration +# 1190| 0: [VariableDeclarationEntry] definition of z +# 1190| Type = [IntType] int +# 1190| init: [Initializer] initializer for z +# 1190| expr: [VariableAccess] y +# 1190| Type = [IntType] int +# 1190| ValueCategory = prvalue(load) +# 1191| 3: [ReturnStmt] return ... +# 1193| [TopLevelFunction] void switch2Case(int) +# 1193| params: +# 1193| 0: [Parameter] x +# 1193| Type = [IntType] int +# 1193| body: [Block] { ... } +# 1194| 0: [DeclStmt] declaration +# 1194| 0: [VariableDeclarationEntry] definition of y +# 1194| Type = [IntType] int +# 1194| init: [Initializer] initializer for y +# 1194| expr: [Literal] 0 +# 1194| Type = [IntType] int +# 1194| Value = [Literal] 0 +# 1194| ValueCategory = prvalue +# 1195| 1: [SwitchStmt] switch (...) ... +# 1195| 0: [VariableAccess] x +# 1195| Type = [IntType] int +# 1195| ValueCategory = prvalue(load) +# 1195| 1: [Block] { ... } +# 1196| 0: [SwitchCase] case ...: +# 1196| 0: [Literal] 1 +# 1196| Type = [IntType] int +# 1196| Value = [Literal] 1 +# 1196| ValueCategory = prvalue +# 1197| 1: [ExprStmt] ExprStmt +# 1197| 0: [AssignExpr] ... = ... +# 1197| Type = [IntType] int +# 1197| ValueCategory = lvalue +# 1197| 0: [VariableAccess] y +# 1197| Type = [IntType] int +# 1197| ValueCategory = lvalue +# 1197| 1: [Literal] 2 +# 1197| Type = [IntType] int +# 1197| Value = [Literal] 2 +# 1197| ValueCategory = prvalue +# 1198| 2: [BreakStmt] break; +# 1199| 3: [SwitchCase] case ...: +# 1199| 0: [Literal] 2 +# 1199| Type = [IntType] int +# 1199| Value = [Literal] 2 +# 1199| ValueCategory = prvalue +# 1200| 4: [ExprStmt] ExprStmt +# 1200| 0: [AssignExpr] ... = ... +# 1200| Type = [IntType] int +# 1200| ValueCategory = lvalue +# 1200| 0: [VariableAccess] y +# 1200| Type = [IntType] int +# 1200| ValueCategory = lvalue +# 1200| 1: [Literal] 3 +# 1200| Type = [IntType] int +# 1200| Value = [Literal] 3 +# 1200| ValueCategory = prvalue +# 1201| 2: [LabelStmt] label ...: +# 1202| 3: [DeclStmt] declaration +# 1202| 0: [VariableDeclarationEntry] definition of z +# 1202| Type = [IntType] int +# 1202| init: [Initializer] initializer for z +# 1202| expr: [VariableAccess] y +# 1202| Type = [IntType] int +# 1202| ValueCategory = prvalue(load) +# 1203| 4: [ReturnStmt] return ... +# 1205| [TopLevelFunction] void switch2Case_default(int) +# 1205| params: +# 1205| 0: [Parameter] x +# 1205| Type = [IntType] int +# 1205| body: [Block] { ... } +# 1206| 0: [DeclStmt] declaration +# 1206| 0: [VariableDeclarationEntry] definition of y +# 1206| Type = [IntType] int +# 1206| init: [Initializer] initializer for y +# 1206| expr: [Literal] 0 +# 1206| Type = [IntType] int +# 1206| Value = [Literal] 0 +# 1206| ValueCategory = prvalue +# 1207| 1: [SwitchStmt] switch (...) ... +# 1207| 0: [VariableAccess] x +# 1207| Type = [IntType] int +# 1207| ValueCategory = prvalue(load) +# 1207| 1: [Block] { ... } +# 1208| 0: [SwitchCase] case ...: +# 1208| 0: [Literal] 1 +# 1208| Type = [IntType] int +# 1208| Value = [Literal] 1 +# 1208| ValueCategory = prvalue +# 1209| 1: [ExprStmt] ExprStmt +# 1209| 0: [AssignExpr] ... = ... +# 1209| Type = [IntType] int +# 1209| ValueCategory = lvalue +# 1209| 0: [VariableAccess] y +# 1209| Type = [IntType] int +# 1209| ValueCategory = lvalue +# 1209| 1: [Literal] 2 +# 1209| Type = [IntType] int +# 1209| Value = [Literal] 2 +# 1209| ValueCategory = prvalue +# 1210| 2: [BreakStmt] break; +# 1212| 3: [SwitchCase] case ...: +# 1212| 0: [Literal] 2 +# 1212| Type = [IntType] int +# 1212| Value = [Literal] 2 +# 1212| ValueCategory = prvalue +# 1213| 4: [ExprStmt] ExprStmt +# 1213| 0: [AssignExpr] ... = ... +# 1213| Type = [IntType] int +# 1213| ValueCategory = lvalue +# 1213| 0: [VariableAccess] y +# 1213| Type = [IntType] int +# 1213| ValueCategory = lvalue +# 1213| 1: [Literal] 3 +# 1213| Type = [IntType] int +# 1213| Value = [Literal] 3 +# 1213| ValueCategory = prvalue +# 1214| 5: [BreakStmt] break; +# 1216| 6: [SwitchCase] default: +# 1217| 7: [ExprStmt] ExprStmt +# 1217| 0: [AssignExpr] ... = ... +# 1217| Type = [IntType] int +# 1217| ValueCategory = lvalue +# 1217| 0: [VariableAccess] y +# 1217| Type = [IntType] int +# 1217| ValueCategory = lvalue +# 1217| 1: [Literal] 4 +# 1217| Type = [IntType] int +# 1217| Value = [Literal] 4 +# 1217| ValueCategory = prvalue +# 1218| 2: [LabelStmt] label ...: +# 1219| 3: [DeclStmt] declaration +# 1219| 0: [VariableDeclarationEntry] definition of z +# 1219| Type = [IntType] int +# 1219| init: [Initializer] initializer for z +# 1219| expr: [VariableAccess] y +# 1219| Type = [IntType] int +# 1219| ValueCategory = prvalue(load) +# 1220| 4: [ReturnStmt] return ... perf-regression.cpp: # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| params: diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 6989287d222..c3a394f0985 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1170,4 +1170,53 @@ String ReturnObjectImpl() { return String("foo"); } +void switch1Case(int x) { + int y = 0; + switch(x) { + case 1: + y = 2; + } + int z = y; +} + +void switch2Case_fallthrough(int x) { + int y = 0; + switch(x) { + case 1: + y = 2; + case 2: + y = 3; + } + int z = y; +} + +void switch2Case(int x) { + int y = 0; + switch(x) { + case 1: + y = 2; + break; + case 2: + y = 3; + } + int z = y; +} + +void switch2Case_default(int x) { + int y = 0; + switch(x) { + case 1: + y = 2; + break; + + case 2: + y = 3; + break; + + default: + y = 4; + } + int z = y; +} + // semmle-extractor-options: -std=c++17 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 6420d52ee6d..d219c17813b 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -6052,6 +6052,173 @@ ir.cpp: # 1169| v1169_8(void) = AliasedUse : ~mu1169_4 # 1169| v1169_9(void) = ExitFunction : +# 1173| void switch1Case(int) +# 1173| Block 0 +# 1173| v1173_1(void) = EnterFunction : +# 1173| mu1173_2(unknown) = AliasedDefinition : +# 1173| mu1173_3(unknown) = InitializeNonLocal : +# 1173| mu1173_4(unknown) = UnmodeledDefinition : +# 1173| r1173_5(glval) = VariableAddress[x] : +# 1173| mu1173_6(int) = InitializeParameter[x] : &:r1173_5 +# 1174| r1174_1(glval) = VariableAddress[y] : +# 1174| r1174_2(int) = Constant[0] : +# 1174| mu1174_3(int) = Store : &:r1174_1, r1174_2 +# 1175| r1175_1(glval) = VariableAddress[x] : +# 1175| r1175_2(int) = Load : &:r1175_1, ~mu1173_4 +# 1175| v1175_3(void) = Switch : r1175_2 +#-----| Case[1] -> Block 1 + +# 1176| Block 1 +# 1176| v1176_1(void) = NoOp : +# 1177| r1177_1(int) = Constant[2] : +# 1177| r1177_2(glval) = VariableAddress[y] : +# 1177| mu1177_3(int) = Store : &:r1177_2, r1177_1 +# 1179| r1179_1(glval) = VariableAddress[z] : +# 1179| r1179_2(glval) = VariableAddress[y] : +# 1179| r1179_3(int) = Load : &:r1179_2, ~mu1173_4 +# 1179| mu1179_4(int) = Store : &:r1179_1, r1179_3 +# 1180| v1180_1(void) = NoOp : +# 1173| v1173_7(void) = ReturnVoid : +# 1173| v1173_8(void) = UnmodeledUse : mu* +# 1173| v1173_9(void) = AliasedUse : ~mu1173_4 +# 1173| v1173_10(void) = ExitFunction : + +# 1182| void switch2Case_fallthrough(int) +# 1182| Block 0 +# 1182| v1182_1(void) = EnterFunction : +# 1182| mu1182_2(unknown) = AliasedDefinition : +# 1182| mu1182_3(unknown) = InitializeNonLocal : +# 1182| mu1182_4(unknown) = UnmodeledDefinition : +# 1182| r1182_5(glval) = VariableAddress[x] : +# 1182| mu1182_6(int) = InitializeParameter[x] : &:r1182_5 +# 1183| r1183_1(glval) = VariableAddress[y] : +# 1183| r1183_2(int) = Constant[0] : +# 1183| mu1183_3(int) = Store : &:r1183_1, r1183_2 +# 1184| r1184_1(glval) = VariableAddress[x] : +# 1184| r1184_2(int) = Load : &:r1184_1, ~mu1182_4 +# 1184| v1184_3(void) = Switch : r1184_2 +#-----| Case[1] -> Block 1 +#-----| Case[2] -> Block 2 + +# 1185| Block 1 +# 1185| v1185_1(void) = NoOp : +# 1186| r1186_1(int) = Constant[2] : +# 1186| r1186_2(glval) = VariableAddress[y] : +# 1186| mu1186_3(int) = Store : &:r1186_2, r1186_1 +#-----| Goto -> Block 2 + +# 1187| Block 2 +# 1187| v1187_1(void) = NoOp : +# 1188| r1188_1(int) = Constant[3] : +# 1188| r1188_2(glval) = VariableAddress[y] : +# 1188| mu1188_3(int) = Store : &:r1188_2, r1188_1 +# 1190| r1190_1(glval) = VariableAddress[z] : +# 1190| r1190_2(glval) = VariableAddress[y] : +# 1190| r1190_3(int) = Load : &:r1190_2, ~mu1182_4 +# 1190| mu1190_4(int) = Store : &:r1190_1, r1190_3 +# 1191| v1191_1(void) = NoOp : +# 1182| v1182_7(void) = ReturnVoid : +# 1182| v1182_8(void) = UnmodeledUse : mu* +# 1182| v1182_9(void) = AliasedUse : ~mu1182_4 +# 1182| v1182_10(void) = ExitFunction : + +# 1193| void switch2Case(int) +# 1193| Block 0 +# 1193| v1193_1(void) = EnterFunction : +# 1193| mu1193_2(unknown) = AliasedDefinition : +# 1193| mu1193_3(unknown) = InitializeNonLocal : +# 1193| mu1193_4(unknown) = UnmodeledDefinition : +# 1193| r1193_5(glval) = VariableAddress[x] : +# 1193| mu1193_6(int) = InitializeParameter[x] : &:r1193_5 +# 1194| r1194_1(glval) = VariableAddress[y] : +# 1194| r1194_2(int) = Constant[0] : +# 1194| mu1194_3(int) = Store : &:r1194_1, r1194_2 +# 1195| r1195_1(glval) = VariableAddress[x] : +# 1195| r1195_2(int) = Load : &:r1195_1, ~mu1193_4 +# 1195| v1195_3(void) = Switch : r1195_2 +#-----| Case[1] -> Block 1 +#-----| Case[2] -> Block 2 + +# 1196| Block 1 +# 1196| v1196_1(void) = NoOp : +# 1197| r1197_1(int) = Constant[2] : +# 1197| r1197_2(glval) = VariableAddress[y] : +# 1197| mu1197_3(int) = Store : &:r1197_2, r1197_1 +# 1198| v1198_1(void) = NoOp : +#-----| Goto -> Block 3 + +# 1199| Block 2 +# 1199| v1199_1(void) = NoOp : +# 1200| r1200_1(int) = Constant[3] : +# 1200| r1200_2(glval) = VariableAddress[y] : +# 1200| mu1200_3(int) = Store : &:r1200_2, r1200_1 +#-----| Goto -> Block 3 + +# 1201| Block 3 +# 1201| v1201_1(void) = NoOp : +# 1202| r1202_1(glval) = VariableAddress[z] : +# 1202| r1202_2(glval) = VariableAddress[y] : +# 1202| r1202_3(int) = Load : &:r1202_2, ~mu1193_4 +# 1202| mu1202_4(int) = Store : &:r1202_1, r1202_3 +# 1203| v1203_1(void) = NoOp : +# 1193| v1193_7(void) = ReturnVoid : +# 1193| v1193_8(void) = UnmodeledUse : mu* +# 1193| v1193_9(void) = AliasedUse : ~mu1193_4 +# 1193| v1193_10(void) = ExitFunction : + +# 1205| void switch2Case_default(int) +# 1205| Block 0 +# 1205| v1205_1(void) = EnterFunction : +# 1205| mu1205_2(unknown) = AliasedDefinition : +# 1205| mu1205_3(unknown) = InitializeNonLocal : +# 1205| mu1205_4(unknown) = UnmodeledDefinition : +# 1205| r1205_5(glval) = VariableAddress[x] : +# 1205| mu1205_6(int) = InitializeParameter[x] : &:r1205_5 +# 1206| r1206_1(glval) = VariableAddress[y] : +# 1206| r1206_2(int) = Constant[0] : +# 1206| mu1206_3(int) = Store : &:r1206_1, r1206_2 +# 1207| r1207_1(glval) = VariableAddress[x] : +# 1207| r1207_2(int) = Load : &:r1207_1, ~mu1205_4 +# 1207| v1207_3(void) = Switch : r1207_2 +#-----| Case[1] -> Block 1 +#-----| Case[2] -> Block 2 +#-----| Default -> Block 3 + +# 1208| Block 1 +# 1208| v1208_1(void) = NoOp : +# 1209| r1209_1(int) = Constant[2] : +# 1209| r1209_2(glval) = VariableAddress[y] : +# 1209| mu1209_3(int) = Store : &:r1209_2, r1209_1 +# 1210| v1210_1(void) = NoOp : +#-----| Goto -> Block 4 + +# 1212| Block 2 +# 1212| v1212_1(void) = NoOp : +# 1213| r1213_1(int) = Constant[3] : +# 1213| r1213_2(glval) = VariableAddress[y] : +# 1213| mu1213_3(int) = Store : &:r1213_2, r1213_1 +# 1214| v1214_1(void) = NoOp : +#-----| Goto -> Block 4 + +# 1216| Block 3 +# 1216| v1216_1(void) = NoOp : +# 1217| r1217_1(int) = Constant[4] : +# 1217| r1217_2(glval) = VariableAddress[y] : +# 1217| mu1217_3(int) = Store : &:r1217_2, r1217_1 +#-----| Goto -> Block 4 + +# 1218| Block 4 +# 1218| v1218_1(void) = NoOp : +# 1219| r1219_1(glval) = VariableAddress[z] : +# 1219| r1219_2(glval) = VariableAddress[y] : +# 1219| r1219_3(int) = Load : &:r1219_2, ~mu1205_4 +# 1219| mu1219_4(int) = Store : &:r1219_1, r1219_3 +# 1220| v1220_1(void) = NoOp : +# 1205| v1205_7(void) = ReturnVoid : +# 1205| v1205_8(void) = UnmodeledUse : mu* +# 1205| v1205_9(void) = AliasedUse : ~mu1205_4 +# 1205| v1205_10(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 From c5f38eecfee0f93ac23926fcfdff41cb518f0a6e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 20 Feb 2020 15:37:02 +0100 Subject: [PATCH 074/134] C++: Fix IR generation and accept output --- .../ir/implementation/raw/internal/TranslatedStmt.qll | 4 ++++ cpp/ql/test/library-tests/ir/ir/raw_ir.expected | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index 43727b3ff0a..72560c78d08 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -655,6 +655,10 @@ class TranslatedSwitchStmt extends TranslatedStmt { kind = getCaseEdge(switchCase) and result = getTranslatedStmt(switchCase).getFirstInstruction() ) + or + not stmt.hasDefaultCase() and + kind instanceof GotoEdge and + result = getParent().getChildSuccessor(this) } override Instruction getChildSuccessor(TranslatedElement child) { diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index d219c17813b..fc630a53a8f 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -6067,12 +6067,16 @@ ir.cpp: # 1175| r1175_2(int) = Load : &:r1175_1, ~mu1173_4 # 1175| v1175_3(void) = Switch : r1175_2 #-----| Case[1] -> Block 1 +#-----| Goto -> Block 2 # 1176| Block 1 # 1176| v1176_1(void) = NoOp : # 1177| r1177_1(int) = Constant[2] : # 1177| r1177_2(glval) = VariableAddress[y] : # 1177| mu1177_3(int) = Store : &:r1177_2, r1177_1 +#-----| Goto -> Block 2 + +# 1179| Block 2 # 1179| r1179_1(glval) = VariableAddress[z] : # 1179| r1179_2(glval) = VariableAddress[y] : # 1179| r1179_3(int) = Load : &:r1179_2, ~mu1173_4 @@ -6099,6 +6103,7 @@ ir.cpp: # 1184| v1184_3(void) = Switch : r1184_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 +#-----| Goto -> Block 3 # 1185| Block 1 # 1185| v1185_1(void) = NoOp : @@ -6112,6 +6117,9 @@ ir.cpp: # 1188| r1188_1(int) = Constant[3] : # 1188| r1188_2(glval) = VariableAddress[y] : # 1188| mu1188_3(int) = Store : &:r1188_2, r1188_1 +#-----| Goto -> Block 3 + +# 1190| Block 3 # 1190| r1190_1(glval) = VariableAddress[z] : # 1190| r1190_2(glval) = VariableAddress[y] : # 1190| r1190_3(int) = Load : &:r1190_2, ~mu1182_4 @@ -6138,6 +6146,7 @@ ir.cpp: # 1195| v1195_3(void) = Switch : r1195_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 +#-----| Goto -> Block 3 # 1196| Block 1 # 1196| v1196_1(void) = NoOp : From 46b226e0c5a654846c109de5f5dbdeeb62457b90 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Thu, 20 Feb 2020 15:41:06 +0000 Subject: [PATCH 075/134] C++: add more extensive test for desugaring of range-based-for loops --- .../range_based_for/range_based_for.expected | 32 ++++++++++++ .../range_based_for/range_based_for.ql | 52 +++++++++++++++++++ .../library-tests/range_based_for/test.cpp | 47 +++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 cpp/ql/test/library-tests/range_based_for/range_based_for.expected create mode 100644 cpp/ql/test/library-tests/range_based_for/range_based_for.ql create mode 100644 cpp/ql/test/library-tests/range_based_for/test.cpp diff --git a/cpp/ql/test/library-tests/range_based_for/range_based_for.expected b/cpp/ql/test/library-tests/range_based_for/range_based_for.expected new file mode 100644 index 00000000000..075acb19427 --- /dev/null +++ b/cpp/ql/test/library-tests/range_based_for/range_based_for.expected @@ -0,0 +1,32 @@ +bodies +| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:28:10:3 | { ... } | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:28:30:3 | { ... } | +| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:27:46:3 | { ... } | +variables +| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:13:8:17 | value | file://:0:0:0:0 | short | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:12:28:16 | value | file://:0:0:0:0 | int | +| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:13:44:17 | value | file://:0:0:0:0 | long | +ranges +| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:21:8:25 | array | file://:0:0:0:0 | short[100] | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:25 | vector | test.cpp:16:8:16:13 | Vector | +| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:21:44:24 | list | file://:0:0:0:0 | const List & | +rangeVariables +| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__range) | file://:0:0:0:0 | short(&)[100] | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:3:28:3 | (__range) | file://:0:0:0:0 | Vector & | +| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__range) | file://:0:0:0:0 | const List & | +conditions +| test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator!= | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | +| test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | +beginVariables +| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__begin) | file://:0:0:0:0 | short * | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:3:28:3 | (__begin) | test.cpp:17:10:17:17 | Iterator | +| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__begin) | file://:0:0:0:0 | long * | +endVariables +| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__end) | file://:0:0:0:0 | short * | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:3:28:3 | (__end) | test.cpp:17:10:17:17 | Iterator | +| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__end) | file://:0:0:0:0 | long * | +updates +| test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator++ | file://:0:0:0:0 | (__begin) | +| test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) | diff --git a/cpp/ql/test/library-tests/range_based_for/range_based_for.ql b/cpp/ql/test/library-tests/range_based_for/range_based_for.ql new file mode 100644 index 00000000000..265899da51a --- /dev/null +++ b/cpp/ql/test/library-tests/range_based_for/range_based_for.ql @@ -0,0 +1,52 @@ +import cpp + +query predicate bodies(RangeBasedForStmt rbf, Stmt body) { body = rbf.getStmt() } + +query predicate variables(RangeBasedForStmt rbf, LocalVariable v, Type t) { + v = rbf.getVariable() and + t = v.getType() +} + +query predicate ranges(RangeBasedForStmt rbf, Expr range, Type t) { + range = rbf.getRange() and + t = range.getType() +} + +query predicate rangeVariables(RangeBasedForStmt rbf, LocalVariable rangeVar, Type t) { + rangeVar = rbf.getRangeVariable() and + t = rangeVar.getType() +} + +query predicate conditions(RangeBasedForStmt rbf, Expr condition, Expr left, Expr right) { + condition = rbf.getCondition() and + ( + condition instanceof BinaryOperation and + left = condition.(BinaryOperation).getLeftOperand() and + right = condition.(BinaryOperation).getRightOperand() + or + condition instanceof FunctionCall and + left = condition.(FunctionCall).getQualifier() and + right = condition.(FunctionCall).getArgument(0) + ) +} + +query predicate beginVariables(RangeBasedForStmt rbf, LocalVariable beginVar, Type t) { + beginVar = rbf.getBeginVariable() and + t = beginVar.getType() +} + +query predicate endVariables(RangeBasedForStmt rbf, LocalVariable endVar, Type t) { + endVar = rbf.getEndVariable() and + t = endVar.getType() +} + +query predicate updates(RangeBasedForStmt rbf, Expr update, Expr operand) { + update = rbf.getUpdate() and + ( + update instanceof UnaryOperation and + operand = update.(UnaryOperation).getOperand() + or + update instanceof FunctionCall and + operand = update.(FunctionCall).getQualifier() + ) +} diff --git a/cpp/ql/test/library-tests/range_based_for/test.cpp b/cpp/ql/test/library-tests/range_based_for/test.cpp new file mode 100644 index 00000000000..83c2b40a4ac --- /dev/null +++ b/cpp/ql/test/library-tests/range_based_for/test.cpp @@ -0,0 +1,47 @@ + +void print_short(short); +void print_int(int); +void print_long(long); + +short array[100]; +void loop_over_c_array() { + for (auto value : array) { + print_short(value); + } +} + +// A class that can be used with range-based-for, because it has the member +// functions `begin` and `end`. +template +struct Vector { + struct Iterator { + const T& operator*() const; + bool operator!=(const Iterator &rhs) const; + Iterator operator++(); + }; + Iterator begin(); + Iterator end(); +}; + +Vector vector; +void loop_over_vector_object() { + for (int value : vector) { + print_int(value); + } +} + +// A class that can be used with range-based-for, because there are `begin` and +// `end` functions that take a `List` as their argument. +template +struct List {}; + +template +T* begin(const List &list); +template +T* end(const List &list); + +void loop_over_list_object(const List &list) { + for (auto value : list) { + print_long(value); + } +} From 913db460b2a5eb34c4d35daacca237f62c124012 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 20 Feb 2020 18:05:37 +0100 Subject: [PATCH 076/134] Python: Add AST support for special operations. These have the form `$name(arg1, arg2, ...)` and currently have no semantics. They may be useful for testing purposes, however. --- python/ql/src/semmle/python/AstGenerated.qll | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/python/ql/src/semmle/python/AstGenerated.qll b/python/ql/src/semmle/python/AstGenerated.qll index fc79a01d8b7..6832b3f2da6 100644 --- a/python/ql/src/semmle/python/AstGenerated.qll +++ b/python/ql/src/semmle/python/AstGenerated.qll @@ -1,3 +1,8 @@ +/* + * This library file is auto-generated by 'semmle/query_gen.py'. + * WARNING: Any modifications to this file will be lost. + * Relations can be changed by modifying master.py. + */ import python library class Add_ extends @py_Add, Operator { @@ -1781,6 +1786,37 @@ library class Slice_ extends @py_Slice, Expr { } +library class SpecialOperation_ extends @py_SpecialOperation, Expr { + + + /** Gets the name of this special operation. */ + string getName() { + py_strs(result, this, 2) + } + + + /** Gets the arguments of this special operation. */ + ExprList getArguments() { + py_expr_lists(result, this, 3) + } + + + /** Gets the nth argument of this special operation. */ + Expr getArgument(int index) { + result = this.getArguments().getItem(index) + } + + /** Gets an argument of this special operation. */ + Expr getAnArgument() { + result = this.getArguments().getAnItem() + } + + override string toString() { + result = "SpecialOperation" + } + +} + library class Starred_ extends @py_Starred, Expr { From a772b82fea47e28244db25199dee0266800d083e Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 20 Feb 2020 19:48:49 +0100 Subject: [PATCH 077/134] Address review comments --- .../cpp/dataflow/internal/DataFlowImpl.qll | 20 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 20 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 20 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 20 +++++++++---------- .../dataflow/internal/DataFlowImplLocal.qll | 20 +++++++++---------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 20 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl2.qll | 20 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl3.qll | 20 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl4.qll | 20 +++++++++---------- .../csharp/dataflow/internal/DataFlowImpl.qll | 20 +++++++++---------- .../dataflow/internal/DataFlowImpl2.qll | 20 +++++++++---------- .../dataflow/internal/DataFlowImpl3.qll | 20 +++++++++---------- .../dataflow/internal/DataFlowImpl4.qll | 20 +++++++++---------- .../dataflow/internal/DataFlowImpl5.qll | 20 +++++++++---------- .../java/dataflow/internal/DataFlowImpl.qll | 20 +++++++++---------- .../java/dataflow/internal/DataFlowImpl2.qll | 20 +++++++++---------- .../java/dataflow/internal/DataFlowImpl3.qll | 20 +++++++++---------- .../java/dataflow/internal/DataFlowImpl4.qll | 20 +++++++++---------- .../java/dataflow/internal/DataFlowImpl5.qll | 20 +++++++++---------- 19 files changed, 171 insertions(+), 209 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index cce49032808..8412e3ea856 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index cce49032808..8412e3ea856 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index cce49032808..8412e3ea856 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index cce49032808..8412e3ea856 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index cce49032808..8412e3ea856 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index cce49032808..8412e3ea856 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index cce49032808..8412e3ea856 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index cce49032808..8412e3ea856 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index cce49032808..8412e3ea856 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index cce49032808..8412e3ea856 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index cce49032808..8412e3ea856 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -422,13 +422,13 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or exists(Node mid | jumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or exists(Node mid | additionalJumpStep(node, mid, config) and - nodeCand1(mid, config) and + nodeCand1(mid, _, config) and toReturn = false ) or @@ -447,10 +447,10 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) or // flow into a callable exists(DataFlowCall call | - nodeCand1ParamArg(call, node, false, config) and + nodeCand1Arg(call, node, false, config) and toReturn = false or - nodeCand1ParamArgToReturn(call, node, config) and + nodeCand1ArgToReturn(call, node, config) and flowInCand1(call, toReturn, config) ) or @@ -468,7 +468,7 @@ private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _ pragma[nomagic] private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, config) and + nodeCand1(out, _, config) and pos = viableReturnPos(call, kind) and out = kind.getAnOutNode(call) ) @@ -484,7 +484,7 @@ private predicate readCand1(Content f, Configuration config) { nodeCandFwd1(node, unbind(config)) and readDirect(node, f, mid) and storeCandFwd1(f, unbind(config)) and - nodeCand1(mid, config) + nodeCand1(mid, _, config) ) } @@ -515,7 +515,7 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1ParamArg( +private predicate nodeCand1Arg( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | @@ -525,10 +525,8 @@ private predicate nodeCand1ParamArg( } pragma[nomagic] -private predicate nodeCand1ParamArgToReturn( - DataFlowCall call, ArgumentNode arg, Configuration config -) { - nodeCand1ParamArg(call, arg, true, config) +private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1Arg(call, arg, true, config) } /** From 7a7444b4e189e0ca610bb4a284cd3f7b7dc3c659 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 20 Feb 2020 12:50:52 -0800 Subject: [PATCH 078/134] Docs: Simplify change note Co-Authored-By: Felicity Chapman --- change-notes/1.24/analysis-cpp.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 600fe398fe0..b4024b73307 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -46,5 +46,5 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. the following improvements: * The library now models data flow through `strdup` and similar functions. * The library now models data flow through formatting functions such as `sprintf`. -* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, removing false positives and adding true positives in many security queries. -* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new intermediate representation to provide a more precise analysis of heap allocated memory and pointers to stack variables. \ No newline at end of file +* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, improving the results of many security queries. +* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new intermediate representation to provide a more precise analysis of heap allocated memory and pointers to stack variables. From 76e5bd59dfea79661a83fa4a6a05cbeaa55356f8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 20 Feb 2020 22:08:16 +0100 Subject: [PATCH 079/134] C++: Change edge to DefaultEdge --- .../code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index 72560c78d08..16197d0e7de 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -657,7 +657,7 @@ class TranslatedSwitchStmt extends TranslatedStmt { ) or not stmt.hasDefaultCase() and - kind instanceof GotoEdge and + kind instanceof DefaultEdge and result = getParent().getChildSuccessor(this) } From 4545ad0f935932a5e02fd09706e380ebdd2a45ee Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 20 Feb 2020 22:09:02 +0100 Subject: [PATCH 080/134] C++: Add sanity check to Instruction.qll --- .../code/cpp/ir/implementation/raw/Instruction.qll | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 4b993849046..cd4bb1cea61 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -268,6 +268,16 @@ module InstructionSanity { } } +query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText +) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) +} + /** * Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified * `File` and line number. Used for assigning register names when printing IR. From 6c0878315838607f3d54eca2bb884c34478b5606 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 20 Feb 2020 22:13:37 +0100 Subject: [PATCH 081/134] C++: Accept output --- cpp/ql/test/library-tests/ir/ir/raw_ir.expected | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index fc630a53a8f..bc7289fd967 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -6067,7 +6067,7 @@ ir.cpp: # 1175| r1175_2(int) = Load : &:r1175_1, ~mu1173_4 # 1175| v1175_3(void) = Switch : r1175_2 #-----| Case[1] -> Block 1 -#-----| Goto -> Block 2 +#-----| Default -> Block 2 # 1176| Block 1 # 1176| v1176_1(void) = NoOp : @@ -6103,7 +6103,7 @@ ir.cpp: # 1184| v1184_3(void) = Switch : r1184_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 -#-----| Goto -> Block 3 +#-----| Default -> Block 3 # 1185| Block 1 # 1185| v1185_1(void) = NoOp : @@ -6146,7 +6146,7 @@ ir.cpp: # 1195| v1195_3(void) = Switch : r1195_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 -#-----| Goto -> Block 3 +#-----| Default -> Block 3 # 1196| Block 1 # 1196| v1196_1(void) = NoOp : From 780010d8f9ae517e4974016cd063d269136bd740 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 20 Feb 2020 22:15:06 +0100 Subject: [PATCH 082/134] C++/C#: Sync identical files --- .../cpp/ir/implementation/aliased_ssa/Instruction.qll | 10 ++++++++++ .../ir/implementation/unaliased_ssa/Instruction.qll | 10 ++++++++++ .../code/csharp/ir/implementation/raw/Instruction.qll | 10 ++++++++++ .../ir/implementation/unaliased_ssa/Instruction.qll | 10 ++++++++++ 4 files changed, 40 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 4b993849046..cd4bb1cea61 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -268,6 +268,16 @@ module InstructionSanity { } } +query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText +) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) +} + /** * Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified * `File` and line number. Used for assigning register names when printing IR. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 4b993849046..cd4bb1cea61 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -268,6 +268,16 @@ module InstructionSanity { } } +query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText +) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) +} + /** * Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified * `File` and line number. Used for assigning register names when printing IR. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 4b993849046..cd4bb1cea61 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -268,6 +268,16 @@ module InstructionSanity { } } +query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText +) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) +} + /** * Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified * `File` and line number. Used for assigning register names when printing IR. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 4b993849046..cd4bb1cea61 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -268,6 +268,16 @@ module InstructionSanity { } } +query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText +) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) +} + /** * Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified * `File` and line number. Used for assigning register names when printing IR. From df7f43ee86e707efae676b61211ce3a54a2b6560 Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Thu, 20 Feb 2020 17:07:56 -0800 Subject: [PATCH 083/134] Adds modernization --- python/ql/src/Expressions/UnnecessaryLambda.ql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Expressions/UnnecessaryLambda.ql b/python/ql/src/Expressions/UnnecessaryLambda.ql index 93b78238e9a..2d7bbf72682 100644 --- a/python/ql/src/Expressions/UnnecessaryLambda.ql +++ b/python/ql/src/Expressions/UnnecessaryLambda.ql @@ -38,14 +38,14 @@ predicate unnecessary_lambda(Lambda l, Expr e) { simple_wrapper(l, e) and ( /* plain class */ - exists(ClassObject c | e.refersTo(c)) + exists(ClassValue c | e.pointsTo(c)) or /* plain function */ - exists(FunctionObject f | e.refersTo(f)) + exists(FunctionValue f | e.pointsTo(f)) or /* bound-method of enclosing instance */ - exists(ClassObject cls, Attribute a | - cls.getPyClass() = l.getScope().getScope() and a = e | + exists(ClassValue cls, Attribute a | + cls.getScope() = l.getScope().getScope() and a = e | ((Name)a.getObject()).getId() = "self" and cls.hasAttribute(a.getName()) ) From fc4afe6eb210106e33e8df2acc17e661817a3dfb Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 21 Feb 2020 09:14:00 +0000 Subject: [PATCH 084/134] JavaScript: Improve qldoc for `Parameter` to clarify that it also contains catch-clause parameters. --- javascript/ql/src/semmle/javascript/Variables.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Variables.qll b/javascript/ql/src/semmle/javascript/Variables.qll index 2c6e7b32647..d83692936f8 100644 --- a/javascript/ql/src/semmle/javascript/Variables.qll +++ b/javascript/ql/src/semmle/javascript/Variables.qll @@ -680,7 +680,7 @@ class Parameterized extends @parameterized, Documentable { } /** - * A parameter declaration. + * A parameter declaration in a function or catch clause. * * Examples: * @@ -688,6 +688,9 @@ class Parameterized extends @parameterized, Documentable { * function f(x, { y: z }, ...rest) { // `x`, `{ y: z }` and `rest` are parameter declarations * var [ a, b ] = rest; * var c; + * try { +* x.m(); + * } catch(e) {} // `e` is a parameter declaration * } * ``` */ From 75495d7aad457a5909336e299405b6df217d5c9b Mon Sep 17 00:00:00 2001 From: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Fri, 21 Feb 2020 10:06:32 +0000 Subject: [PATCH 085/134] Update javascript/ql/src/semmle/javascript/Variables.qll Co-Authored-By: Asger F --- javascript/ql/src/semmle/javascript/Variables.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Variables.qll b/javascript/ql/src/semmle/javascript/Variables.qll index d83692936f8..df4dccaf987 100644 --- a/javascript/ql/src/semmle/javascript/Variables.qll +++ b/javascript/ql/src/semmle/javascript/Variables.qll @@ -689,7 +689,7 @@ class Parameterized extends @parameterized, Documentable { * var [ a, b ] = rest; * var c; * try { -* x.m(); + * x.m(); * } catch(e) {} // `e` is a parameter declaration * } * ``` From 01fed95fe6854be8f727edc5f7d84ce8532cf800 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 11:49:20 +0000 Subject: [PATCH 086/134] JS: Add change note --- change-notes/1.24/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 47fb2dc590b..58c1698d799 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -13,6 +13,8 @@ * The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries. +* Calls can now be resolved to class members in more cases, leading to more results from the security queries. + * Support for the following frameworks and libraries has been improved: - [Electron](https://electronjs.org/) - [Handlebars](https://www.npmjs.com/package/handlebars) From da41cbca065cf71d6cef4ec6b4be45eedc0dfb4c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 21 Feb 2020 13:33:54 +0100 Subject: [PATCH 087/134] C#: Add similar fix to translation of switch statements in C# --- .../csharp/ir/implementation/raw/internal/TranslatedStmt.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll index 5ead54f0a8a..b4a16584434 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -834,6 +834,10 @@ class TranslatedSwitchStmt extends TranslatedStmt { kind = this.getCaseEdge(caseStmt) and result = getTranslatedStmt(caseStmt).getFirstInstruction() ) + or + not exists(stmt.getDefaultCase()) and + kind instanceof DefaultEdge and + result = getParent().getChildSuccessor(this) } private EdgeKind getCaseEdge(CaseStmt caseStmt) { From 8c36b999ccb7f8f63dda44e102a64029ff276b35 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 11:01:52 +0000 Subject: [PATCH 088/134] JS: Track flow into calls to bound functions --- .../semmle/javascript/dataflow/DataFlow.qll | 2 +- .../dataflow/internal/CallGraphs.qll | 12 ++++--- .../dataflow/internal/FlowSteps.qll | 21 ++++++++++++ .../CallGraphs/AnnotatedTest/Test.expected | 4 +-- .../CallGraphs/AnnotatedTest/Test.ql | 33 +++++++++++++++---- .../AnnotatedTest/bound-function.js | 31 +++++++++++++++++ 6 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/bound-function.js diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 5f97f0845bb..e4c1097b877 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -147,7 +147,7 @@ module DataFlow { final FunctionNode getABoundFunctionValue(int boundArgs) { result = getAFunctionValue() and boundArgs = 0 or - CallGraph::getABoundFunctionReference(result, boundArgs).flowsTo(this) + CallGraph::getABoundFunctionReference(result, boundArgs, _).flowsTo(this) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll index d58a83fa0bd..51bd466215e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll @@ -74,7 +74,7 @@ module CallGraph { */ pragma[nomagic] private - DataFlow::SourceNode getABoundFunctionReference(DataFlow::FunctionNode function, int boundArgs, DataFlow::TypeTracker t) { + DataFlow::SourceNode getABoundFunctionReferenceAux(DataFlow::FunctionNode function, int boundArgs, DataFlow::TypeTracker t) { exists(DataFlow::PartialInvokeNode partial, DataFlow::Node callback | result = partial.getBoundFunction(callback, boundArgs) and getAFunctionReference(function, 0, t.continue()).flowsTo(callback) @@ -90,7 +90,7 @@ module CallGraph { private DataFlow::SourceNode getABoundFunctionReferenceAux(DataFlow::FunctionNode function, int boundArgs, DataFlow::TypeTracker t, DataFlow::StepSummary summary) { exists(DataFlow::SourceNode prev | - prev = getABoundFunctionReference(function, boundArgs, t) and + prev = getABoundFunctionReferenceAux(function, boundArgs, t) and DataFlow::StepSummary::step(prev, result, summary) ) } @@ -100,8 +100,12 @@ module CallGraph { * with `function` as the underlying function. */ cached - DataFlow::SourceNode getABoundFunctionReference(DataFlow::FunctionNode function, int boundArgs) { - result = getABoundFunctionReference(function, boundArgs, DataFlow::TypeTracker::end()) + DataFlow::SourceNode getABoundFunctionReference(DataFlow::FunctionNode function, int boundArgs, boolean contextDependent) { + exists(DataFlow::TypeTracker t | + result = getABoundFunctionReferenceAux(function, boundArgs, t) and + t.end() and + contextDependent = t.hasCall() + ) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index bd3e5462116..daa2b9ac8a7 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -6,6 +6,7 @@ import javascript import semmle.javascript.dataflow.Configuration +import semmle.javascript.dataflow.internal.CallGraphs /** * Holds if flow should be tracked through properties of `obj`. @@ -91,6 +92,18 @@ private module CachedSteps { cached predicate calls(DataFlow::InvokeNode invk, Function f) { f = invk.getACallee(0) } + /** + * Holds if `invk` may invoke a bound version of `f` with `boundArgs` already bound. + * + * The receiver is assumed to be bound as well, and should not propagate into `f`. + * + * Does not hold for context-dependent call sites, such as callback invocations. + */ + cached + predicate callsBound(DataFlow::InvokeNode invk, Function f, int boundArgs) { + CallGraph::getABoundFunctionReference(f.flow(), boundArgs, false).flowsTo(invk.getCalleeNode()) + } + /** * Holds if `invk` may invoke `f` indirectly through the given `callback` argument. * @@ -141,6 +154,14 @@ private module CachedSteps { partiallyCalls(invk, callback, f) and parm = DataFlow::thisNode(f) ) + or + exists(int boundArgs, int i, Parameter p | + callsBound(invk, f, boundArgs) and + f.getParameter(boundArgs + i) = p and + not p.isRestParameter() and + arg = invk.getArgument(i) and + parm = DataFlow::parameterNode(p) + ) } /** diff --git a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected index 7257e488e92..b8e143dc5a6 100644 --- a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected +++ b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected @@ -1,5 +1,5 @@ spuriousCallee missingCallee -| constructor-field.ts:40:5:40:14 | f3.build() | constructor-field.ts:13:3:13:12 | build() {} | -| constructor-field.ts:71:1:71:11 | bf3.build() | constructor-field.ts:13:3:13:12 | build() {} | +| constructor-field.ts:40:5:40:14 | f3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | +| constructor-field.ts:71:1:71:11 | bf3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | badAnnotation diff --git a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql index 705ad7eb661..dd41c794213 100644 --- a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql +++ b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql @@ -33,16 +33,37 @@ class AnnotatedCall extends InvokeExpr { string getCallTargetName() { result = calls } AnnotatedFunction getAnExpectedCallee() { result.getCalleeName() = getCallTargetName() } + + int getBoundArgs() { + result = getAnnotation(this, "boundArgs").toInt() + } + + int getBoundArgsOrMinusOne() { + result = getBoundArgs() + or + not exists(getBoundArgs()) and + result = -1 + } } -query predicate spuriousCallee(AnnotatedCall call, AnnotatedFunction target) { - FlowSteps::calls(call.flow(), target) and - not target = call.getAnExpectedCallee() +predicate callEdge(AnnotatedCall call, AnnotatedFunction target, int boundArgs) { + FlowSteps::calls(call.flow(), target) and boundArgs = -1 + or + FlowSteps::callsBound(call.flow(), target, boundArgs) } -query predicate missingCallee(AnnotatedCall call, AnnotatedFunction target) { - not FlowSteps::calls(call.flow(), target) and - target = call.getAnExpectedCallee() +query predicate spuriousCallee(AnnotatedCall call, AnnotatedFunction target, int boundArgs) { + callEdge(call, target, boundArgs) and + not ( + target = call.getAnExpectedCallee() and + boundArgs = call.getBoundArgsOrMinusOne() + ) +} + +query predicate missingCallee(AnnotatedCall call, AnnotatedFunction target, int boundArgs) { + not callEdge(call, target, boundArgs) and + target = call.getAnExpectedCallee() and + boundArgs = call.getBoundArgsOrMinusOne() } query predicate badAnnotation(string name) { diff --git a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/bound-function.js b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/bound-function.js new file mode 100644 index 00000000000..ebce2493639 --- /dev/null +++ b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/bound-function.js @@ -0,0 +1,31 @@ +var url = require('url') +var http = require('http') + +function Mount () {} + +/** name:mount.serve */ +Mount.prototype.serve = function (x) { +} + +function makeMount() { + var m = new Mount() + return m.serve.bind(m); +} + +function makeMount2(x) { + var m = new Mount() + return m.serve.bind(m, x); +} + +var mount = makeMount() +var mount2 = makeMount2(null); + +http.createServer(function (req, res) { + /** calls:mount.serve */ + /** boundArgs:0 */ + mount(req, res) + + /** calls:mount.serve */ + /** boundArgs:1 */ + mount2(res) +}); From e8e649102ff87ac08fe891860013e3efd9c74c8e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 11:04:29 +0000 Subject: [PATCH 089/134] JS: Also propagate out of returns --- .../javascript/dataflow/Configuration.qll | 4 +- .../dataflow/internal/FlowSteps.qll | 8 ++- .../TaintTracking/BasicTaintTracking.expected | 5 ++ .../TaintTracking/DataFlowTracking.expected | 5 ++ .../TaintTracking/bound-function.js | 55 +++++++++++++++++++ 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/library-tests/TaintTracking/bound-function.js diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 9a1cbd31db0..4ae2e2de70f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -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 diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index daa2b9ac8a7..fd2e5112f12 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -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)) } } - diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 097f3559794..1e60ae67461 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -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 | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 5a6ef361bb8..acf3e78e9ad 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -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 | diff --git a/javascript/ql/test/library-tests/TaintTracking/bound-function.js b/javascript/ql/test/library-tests/TaintTracking/bound-function.js new file mode 100644 index 00000000000..abac7b0de33 --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/bound-function.js @@ -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 From b780bc4d5937ddba70e156b0105c77ae4c8ab410 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 12:55:52 +0000 Subject: [PATCH 090/134] JS: Also track into callbacks --- .../semmle/javascript/dataflow/Configuration.qll | 13 +++++++++++-- .../javascript/dataflow/internal/FlowSteps.qll | 14 ++++++++++++++ .../TaintTracking/BasicTaintTracking.expected | 1 + .../TaintTracking/DataFlowTracking.expected | 1 + .../library-tests/TaintTracking/bound-function.js | 2 +- 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 4ae2e2de70f..f71b6982f1e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -71,6 +71,7 @@ private import javascript private import internal.FlowSteps private import internal.AccessPaths +private import internal.CallGraphs /** * A data flow tracking configuration for finding inter-procedural paths from @@ -620,10 +621,11 @@ private predicate exploratoryFlowStep( isAdditionalStoreStep(pred, succ, _, cfg) or isAdditionalLoadStep(pred, succ, _, cfg) or isAdditionalLoadStoreStep(pred, succ, _, cfg) or - // the following two disjuncts taken together over-approximate flow through + // the following three disjuncts taken together over-approximate flow through // higher-order calls callback(pred, succ) or - succ = pred.(DataFlow::FunctionNode).getAParameter() + succ = pred.(DataFlow::FunctionNode).getAParameter() or + exploratoryBoundInvokeStep(pred, succ) } /** @@ -1032,6 +1034,13 @@ private predicate flowIntoHigherOrderCall( succ = cb.getParameter(i) and summary = oldSummary.append(PathSummary::call()) ) + or + exists(DataFlow::SourceNode cb, DataFlow::FunctionNode f, int i, int boundArgs, PathSummary oldSummary | + higherOrderCall(pred, cb, i, cfg, oldSummary) and + cb = CallGraph::getABoundFunctionReference(f, boundArgs, false) and + succ = f.getParameter(boundArgs + i) and + summary = oldSummary.append(PathSummary::call()) + ) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index fd2e5112f12..d01c8ca9e8a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -104,6 +104,20 @@ private module CachedSteps { CallGraph::getABoundFunctionReference(f.flow(), boundArgs, false).flowsTo(invk.getCalleeNode()) } + /** + * Holds if `pred` may flow to `succ` through an invocation of a bound function. + * + * Should only be used for graph pruning, as the edge may lead to spurious flow. + */ + cached + predicate exploratoryBoundInvokeStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::InvokeNode invk, DataFlow::FunctionNode f, int i, int boundArgs | + CallGraph::getABoundFunctionReference(f, boundArgs, _).flowsTo(invk.getCalleeNode()) and + pred = invk.getArgument(i) and + succ = f.getParameter(i + boundArgs) + ) + } + /** * Holds if `invk` may invoke `f` indirectly through the given `callback` argument. * diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 1e60ae67461..53dbe8d1b53 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -17,6 +17,7 @@ typeInferenceMismatch | 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:22:8:22:15 | source() | bound-function.js:25:10:25: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() | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index acf3e78e9ad..127d58056ae 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -8,6 +8,7 @@ | 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:22:8:22:15 | source() | bound-function.js:25:10:25: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() | diff --git a/javascript/ql/test/library-tests/TaintTracking/bound-function.js b/javascript/ql/test/library-tests/TaintTracking/bound-function.js index abac7b0de33..b38dee1c922 100644 --- a/javascript/ql/test/library-tests/TaintTracking/bound-function.js +++ b/javascript/ql/test/library-tests/TaintTracking/bound-function.js @@ -19,7 +19,7 @@ foo2(null, source()); // OK function takesCallback(cb) { - cb(source()); // NOT OK - but not found + cb(source()); // NOT OK } function callback(x, y) { sink(y); From a673539c98d311e3e1b5d1cf44034668aca4af60 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 18 Feb 2020 10:22:24 +0000 Subject: [PATCH 091/134] JS: Update expected output --- .../test/library-tests/InterProceduralFlow/DataFlow.expected | 4 ++++ .../library-tests/InterProceduralFlow/GermanFlow.expected | 4 ++++ .../library-tests/InterProceduralFlow/TaintTracking.expected | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected b/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected index 24e5f967f9f..a7fa3a0de3b 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected @@ -22,6 +22,10 @@ | partial.js:5:15:5:24 | "tainted1" | partial.js:15:15:15:15 | x | | partial.js:5:15:5:24 | "tainted1" | partial.js:21:15:21:15 | x | | partial.js:5:15:5:24 | "tainted1" | partial.js:27:15:27:15 | x | +| partial.js:6:15:6:24 | "tainted2" | partial.js:10:15:10:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:16:15:16:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:22:15:22:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:28:15:28:15 | y | | promises.js:2:16:2:24 | "tainted" | promises.js:7:16:7:18 | val | | promises.js:2:16:2:24 | "tainted" | promises.js:38:32:38:32 | v | | promises.js:11:22:11:31 | "resolved" | promises.js:19:20:19:20 | v | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected b/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected index 9c3980797ea..377eec8c75a 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected @@ -23,6 +23,10 @@ | partial.js:5:15:5:24 | "tainted1" | partial.js:15:15:15:15 | x | | partial.js:5:15:5:24 | "tainted1" | partial.js:21:15:21:15 | x | | partial.js:5:15:5:24 | "tainted1" | partial.js:27:15:27:15 | x | +| partial.js:6:15:6:24 | "tainted2" | partial.js:10:15:10:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:16:15:16:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:22:15:22:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:28:15:28:15 | y | | promises.js:2:16:2:24 | "tainted" | promises.js:7:16:7:18 | val | | promises.js:2:16:2:24 | "tainted" | promises.js:38:32:38:32 | v | | promises.js:11:22:11:31 | "resolved" | promises.js:19:20:19:20 | v | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected b/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected index 5c252b4aeea..b6122f6e2a4 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/TaintTracking.expected @@ -27,6 +27,10 @@ | partial.js:5:15:5:24 | "tainted1" | partial.js:15:15:15:15 | x | | partial.js:5:15:5:24 | "tainted1" | partial.js:21:15:21:15 | x | | partial.js:5:15:5:24 | "tainted1" | partial.js:27:15:27:15 | x | +| partial.js:6:15:6:24 | "tainted2" | partial.js:10:15:10:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:16:15:16:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:22:15:22:15 | y | +| partial.js:6:15:6:24 | "tainted2" | partial.js:28:15:28:15 | y | | promises.js:2:16:2:24 | "tainted" | promises.js:7:16:7:18 | val | | promises.js:2:16:2:24 | "tainted" | promises.js:38:32:38:32 | v | | promises.js:11:22:11:31 | "resolved" | promises.js:19:20:19:20 | v | From 1ee112a3413fa5739229c5588409793dfedad15f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 13:55:27 +0000 Subject: [PATCH 092/134] JS: Add change note --- change-notes/1.24/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 58c1698d799..5465bcdb6ae 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -15,6 +15,8 @@ * Calls can now be resolved to class members in more cases, leading to more results from the security queries. +* Calls through partial invocations such as `.bind()` are now analyzed more precisely, leading to more results from the security queries. + * Support for the following frameworks and libraries has been improved: - [Electron](https://electronjs.org/) - [Handlebars](https://www.npmjs.com/package/handlebars) From d9753b0ca5595f964025d2faec096e302f0f23fc Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 21 Feb 2020 15:09:53 +0100 Subject: [PATCH 093/134] C++/C#: Accept test output after adding sanity check to Instruction.qll --- cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected | 1 + .../test/library-tests/dataflow/dataflow-tests/test_ir.expected | 2 ++ .../test/library-tests/ir/constant_func/constant_func.expected | 2 ++ cpp/ql/test/library-tests/ir/escape/escape.expected | 2 ++ cpp/ql/test/library-tests/ir/escape/ssa_escape.expected | 2 ++ .../rangeanalysis/rangeanalysis/RangeAnalysis.expected | 2 ++ .../rangeanalysis/signanalysis/SignAnalysis.expected | 2 ++ .../valuenumbering/GlobalValueNumbering/diff_ir_expr.expected | 2 ++ .../valuenumbering/GlobalValueNumbering/ir_uniqueness.expected | 2 ++ .../RedundantNullCheckSimple/RedundantNullCheckSimple.expected | 2 ++ csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected | 2 ++ .../test/library-tests/ir/rangeanalysis/RangeAnalysis.expected | 2 ++ 12 files changed, 23 insertions(+) diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected index 110fb218b5f..f481b8d1288 100644 --- a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected @@ -1,3 +1,4 @@ +switchInstructionWithoutDefaultEdge astGuards | test.c:7:9:7:13 | ... > ... | | test.c:17:8:17:12 | ... < ... | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 275cbabc075..34977184a97 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +#select | BarrierGuard.cpp:9:10:9:15 | source | BarrierGuard.cpp:5:19:5:24 | source | | BarrierGuard.cpp:15:10:15:15 | source | BarrierGuard.cpp:13:17:13:22 | source | | BarrierGuard.cpp:25:10:25:15 | source | BarrierGuard.cpp:21:17:21:22 | source | diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected b/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected index 3cba189a0ab..e9dd27b3d79 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +#select | constant_func.cpp:1:5:1:18 | IR: ReturnConstant | 7 | | constant_func.cpp:5:5:5:21 | IR: ReturnConstantPhi | 7 | | constant_func.cpp:25:5:25:25 | IR: ReturnConstantPhiLoop | 7 | diff --git a/cpp/ql/test/library-tests/ir/escape/escape.expected b/cpp/ql/test/library-tests/ir/escape/escape.expected index e69de29bb2d..15f6a5fb8d6 100644 --- a/cpp/ql/test/library-tests/ir/escape/escape.expected +++ b/cpp/ql/test/library-tests/ir/escape/escape.expected @@ -0,0 +1,2 @@ +switchInstructionWithoutDefaultEdge +#select diff --git a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected index e69de29bb2d..15f6a5fb8d6 100644 --- a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected +++ b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected @@ -0,0 +1,2 @@ +switchInstructionWithoutDefaultEdge +#select diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected index be768a4a82f..6bbb4ed3aeb 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +instructionBounds | test.cpp:10:10:10:10 | Store: x | test.cpp:6:15:6:15 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | | test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:7:7:7:11 | test.cpp:7:7:7:11 | | test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected index 961e4b3a201..1dfff37682c 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +#select | binary_logical_operator.c:2:11:2:25 | Constant: ... && ... | positive strictlyPositive | | binary_logical_operator.c:2:11:2:25 | Load: ... && ... | positive | | binary_logical_operator.c:2:11:2:25 | Phi: ... && ... | positive | diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected index cd44eb8572b..f6a8f35a17a 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +#select | test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only | | test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only | | test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only | diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected index e69de29bb2d..15f6a5fb8d6 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected @@ -0,0 +1,2 @@ +switchInstructionWithoutDefaultEdge +#select diff --git a/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected b/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected index 34b7957b817..06c3468a1ee 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +#select | RedundantNullCheckSimple.cpp:4:7:4:7 | Load: p | This null check is redundant because the value is $@ in any case | RedundantNullCheckSimple.cpp:3:7:3:8 | Load: * ... | dereferenced here | | RedundantNullCheckSimple.cpp:13:8:13:8 | Load: p | This null check is redundant because the value is $@ in any case | RedundantNullCheckSimple.cpp:10:11:10:12 | Load: * ... | dereferenced here | | RedundantNullCheckSimple.cpp:20:7:20:8 | Load: * ... | This null check is redundant because the value is $@ in any case | RedundantNullCheckSimple.cpp:19:7:19:9 | Load: * ... | dereferenced here | diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected index 0c16c9ff134..01095bdd4d3 100644 --- a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected +++ b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +#select | test.cs:21:17:21:21 | Test2 | test.cs:34:41:34:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | | test.cs:56:17:56:21 | Test4 | test.cs:67:41:67:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | | test.cs:71:17:71:21 | Test5 | test.cs:77:22:77:27 | access to indexer | This array access might be out of bounds, as the index might be equal to the array length | diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected index 329bbd3bff0..02f49691a53 100644 --- a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected @@ -1,3 +1,5 @@ +switchInstructionWithoutDefaultEdge +instructionBounds | test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:24:16:24 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | | test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cs:18:9:18:13 | test.cs:18:9:18:13 | | test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | From d1df251b9225b47f35facc121f0ed5a72fee0734 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 14:38:33 +0000 Subject: [PATCH 094/134] JS: Proto pollution: Add is-plain-object sanitizer --- .../CWE-400/PrototypePollutionUtility.ql | 22 ++++++++++++++++++- .../PrototypePollutionUtility/tests.js | 11 ++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index 317aa6fcc22..59f637e95ef 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -199,7 +199,8 @@ class PropNameTracking extends DataFlow::Configuration { node instanceof InstanceOfGuard or node instanceof TypeofGuard or node instanceof BlacklistInclusionGuard or - node instanceof WhitelistInclusionGuard + node instanceof WhitelistInclusionGuard or + node instanceof IsPlainObjectGuard } } @@ -374,6 +375,25 @@ class WhitelistInclusionGuard extends DataFlow::LabeledBarrierGuardNode { } } +/** + * A check of form `isPlainObject(e)` or similar, which sanitizes the `constructor` + * payload in the true case, since it rejects objects with a non-standard `constructor` + * property. + */ +class IsPlainObjectGuard extends DataFlow::LabeledBarrierGuardNode, DataFlow::CallNode { + IsPlainObjectGuard() { + exists(string name | name = "is-plain-object" or name = "is-extendable" | + this = moduleImport(name).getACall() + ) + } + + override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) { + e = getArgument(0).asExpr() and + outcome = true and + lbl = "constructor" + } +} + /** * Gets a meaningful name for `node` if possible. */ diff --git a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js index 2de68103c63..0c929e75093 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js +++ b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js @@ -462,3 +462,14 @@ function copyUsingUnderscoreOrLodash(dst, src) { } }); } + +let isPlainObject = require('is-plain-object'); +function copyPlainObject(dst, src) { + for (let key in src) { + if (dst[key] && isPlainObject(src)) { + copyPlainObject(dst[key], src[key]); + } else { + dst[key] = src[key]; // OK + } + } +} From af364e66fc1c83157f311725cde6fe81a9e54c70 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sun, 23 Feb 2020 20:53:49 +0100 Subject: [PATCH 095/134] C++/C#: Move sanity check inside InstructionSanity module and accept tests --- .../implementation/aliased_ssa/Instruction.qll | 18 +++++++++--------- .../cpp/ir/implementation/raw/Instruction.qll | 18 +++++++++--------- .../unaliased_ssa/Instruction.qll | 18 +++++++++--------- .../controlflow/guards-ir/tests.expected | 1 - .../dataflow/dataflow-tests/test_ir.expected | 2 -- .../ir/constant_func/constant_func.expected | 2 -- .../library-tests/ir/escape/escape.expected | 2 -- .../ir/escape/ssa_escape.expected | 2 -- .../ir/ir/aliased_ssa_sanity.expected | 1 + .../ir/ir/aliased_ssa_sanity_unsound.expected | 1 + .../library-tests/ir/ir/raw_sanity.expected | 1 + .../ir/ir/unaliased_ssa_sanity.expected | 1 + .../ir/unaliased_ssa_sanity_unsound.expected | 1 + .../ir/ssa/aliased_ssa_sanity.expected | 1 + .../ir/ssa/aliased_ssa_sanity_unsound.expected | 1 + .../ir/ssa/unaliased_ssa_sanity.expected | 1 + .../ssa/unaliased_ssa_sanity_unsound.expected | 1 + .../rangeanalysis/RangeAnalysis.expected | 2 -- .../signanalysis/SignAnalysis.expected | 2 -- .../syntax-zoo/aliased_ssa_sanity.expected | 1 + .../syntax-zoo/raw_sanity.expected | 1 + .../syntax-zoo/unaliased_ssa_sanity.expected | 1 + .../GlobalValueNumbering/diff_ir_expr.expected | 2 -- .../ir_uniqueness.expected | 2 -- .../RedundantNullCheckSimple.expected | 2 -- .../ir/implementation/raw/Instruction.qll | 18 +++++++++--------- .../unaliased_ssa/Instruction.qll | 18 +++++++++--------- .../library-tests/ir/ir/raw_ir_sanity.expected | 1 + .../ir/ir/unaliased_ssa_sanity.expected | 1 + .../ir/offbyone/OffByOneRA.expected | 2 -- .../ir/rangeanalysis/RangeAnalysis.expected | 2 -- 31 files changed, 59 insertions(+), 68 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index cd4bb1cea61..d058a6c5a3e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -266,16 +266,16 @@ module InstructionSanity { funcText = Language::getIdentityString(func.getFunction()) ) } -} -query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText -) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index cd4bb1cea61..d058a6c5a3e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -266,16 +266,16 @@ module InstructionSanity { funcText = Language::getIdentityString(func.getFunction()) ) } -} -query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText -) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index cd4bb1cea61..d058a6c5a3e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -266,16 +266,16 @@ module InstructionSanity { funcText = Language::getIdentityString(func.getFunction()) ) } -} -query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText -) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } } /** diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected index f481b8d1288..110fb218b5f 100644 --- a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected @@ -1,4 +1,3 @@ -switchInstructionWithoutDefaultEdge astGuards | test.c:7:9:7:13 | ... > ... | | test.c:17:8:17:12 | ... < ... | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 34977184a97..275cbabc075 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -#select | BarrierGuard.cpp:9:10:9:15 | source | BarrierGuard.cpp:5:19:5:24 | source | | BarrierGuard.cpp:15:10:15:15 | source | BarrierGuard.cpp:13:17:13:22 | source | | BarrierGuard.cpp:25:10:25:15 | source | BarrierGuard.cpp:21:17:21:22 | source | diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected b/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected index e9dd27b3d79..3cba189a0ab 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -#select | constant_func.cpp:1:5:1:18 | IR: ReturnConstant | 7 | | constant_func.cpp:5:5:5:21 | IR: ReturnConstantPhi | 7 | | constant_func.cpp:25:5:25:25 | IR: ReturnConstantPhiLoop | 7 | diff --git a/cpp/ql/test/library-tests/ir/escape/escape.expected b/cpp/ql/test/library-tests/ir/escape/escape.expected index 15f6a5fb8d6..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/escape/escape.expected +++ b/cpp/ql/test/library-tests/ir/escape/escape.expected @@ -1,2 +0,0 @@ -switchInstructionWithoutDefaultEdge -#select diff --git a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected index 15f6a5fb8d6..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected +++ b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected @@ -1,2 +0,0 @@ -switchInstructionWithoutDefaultEdge -#select diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected index e5e666c020b..289b7bcae86 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -19,6 +19,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected index e5e666c020b..289b7bcae86 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected @@ -19,6 +19,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected index e5e666c020b..289b7bcae86 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected @@ -19,6 +19,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index e5e666c020b..289b7bcae86 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -19,6 +19,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected index e5e666c020b..289b7bcae86 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected @@ -19,6 +19,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected index 9769ee11f99..962a5a4484b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected @@ -15,6 +15,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected index 9769ee11f99..962a5a4484b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected @@ -15,6 +15,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected index 9769ee11f99..962a5a4484b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected @@ -15,6 +15,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected index 9769ee11f99..962a5a4484b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected @@ -15,6 +15,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected index 6bbb4ed3aeb..be768a4a82f 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -instructionBounds | test.cpp:10:10:10:10 | Store: x | test.cpp:6:15:6:15 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | | test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:7:7:7:11 | test.cpp:7:7:7:11 | | test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected index 1dfff37682c..961e4b3a201 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -#select | binary_logical_operator.c:2:11:2:25 | Constant: ... && ... | positive strictlyPositive | | binary_logical_operator.c:2:11:2:25 | Load: ... && ... | positive | | binary_logical_operator.c:2:11:2:25 | Phi: ... && ... | positive | diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index c0671e967cc..64a52186564 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -568,6 +568,7 @@ lostReachability | range_analysis.c:371:37:371:39 | Constant: 500 | backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index 80da8a79ced..63e211635ea 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -645,6 +645,7 @@ useNotDominatedByDefinition | pointer_to_member.cpp:36:22:36:28 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | | try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) | | vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | IR: main | int main(int, char**) | +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index c7897f98817..a7f2d82ac7e 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -577,6 +577,7 @@ lostReachability | range_analysis.c:371:37:371:39 | Constant: 500 | backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected index f6a8f35a17a..cd44eb8572b 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -#select | test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only | | test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only | | test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only | diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected index 15f6a5fb8d6..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected @@ -1,2 +0,0 @@ -switchInstructionWithoutDefaultEdge -#select diff --git a/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected b/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected index 06c3468a1ee..34b7957b817 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/RedundantNullCheckSimple/RedundantNullCheckSimple.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -#select | RedundantNullCheckSimple.cpp:4:7:4:7 | Load: p | This null check is redundant because the value is $@ in any case | RedundantNullCheckSimple.cpp:3:7:3:8 | Load: * ... | dereferenced here | | RedundantNullCheckSimple.cpp:13:8:13:8 | Load: p | This null check is redundant because the value is $@ in any case | RedundantNullCheckSimple.cpp:10:11:10:12 | Load: * ... | dereferenced here | | RedundantNullCheckSimple.cpp:20:7:20:8 | Load: * ... | This null check is redundant because the value is $@ in any case | RedundantNullCheckSimple.cpp:19:7:19:9 | Load: * ... | dereferenced here | diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index cd4bb1cea61..d058a6c5a3e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -266,16 +266,16 @@ module InstructionSanity { funcText = Language::getIdentityString(func.getFunction()) ) } -} -query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText -) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index cd4bb1cea61..d058a6c5a3e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -266,16 +266,16 @@ module InstructionSanity { funcText = Language::getIdentityString(func.getFunction()) ) } -} -query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText -) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } } /** diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected index 9f132fa6f28..4c0b8578a17 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected @@ -15,6 +15,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index 9f132fa6f28..4c0b8578a17 100644 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -15,6 +15,7 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +switchInstructionWithoutDefaultEdge missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected index 01095bdd4d3..0c16c9ff134 100644 --- a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected +++ b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -#select | test.cs:21:17:21:21 | Test2 | test.cs:34:41:34:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | | test.cs:56:17:56:21 | Test4 | test.cs:67:41:67:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | | test.cs:71:17:71:21 | Test5 | test.cs:77:22:77:27 | access to indexer | This array access might be out of bounds, as the index might be equal to the array length | diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected index 02f49691a53..329bbd3bff0 100644 --- a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected @@ -1,5 +1,3 @@ -switchInstructionWithoutDefaultEdge -instructionBounds | test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:24:16:24 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | | test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cs:18:9:18:13 | test.cs:18:9:18:13 | | test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | From ed430ce8554818a6a69d30ad6c990aaa60942209 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 24 Feb 2020 09:12:14 +0100 Subject: [PATCH 096/134] C++/C#: Bind parameter in new case. --- .../code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll | 1 + .../csharp/ir/implementation/raw/internal/TranslatedStmt.qll | 1 + 2 files changed, 2 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index 16197d0e7de..88a7d4c99ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -657,6 +657,7 @@ class TranslatedSwitchStmt extends TranslatedStmt { ) or not stmt.hasDefaultCase() and + tag = SwitchBranchTag() and kind instanceof DefaultEdge and result = getParent().getChildSuccessor(this) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll index b4a16584434..0ec51bd9190 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -836,6 +836,7 @@ class TranslatedSwitchStmt extends TranslatedStmt { ) or not exists(stmt.getDefaultCase()) and + tag = SwitchBranchTag() and kind instanceof DefaultEdge and result = getParent().getChildSuccessor(this) } From f923b24bc57bf25b23b4172b507e9d5cf8ba9c17 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 11:16:55 +0000 Subject: [PATCH 097/134] JS: Fix test --- .../PrototypePollutionUtility.expected | 107 ++++++++++++++++++ .../PrototypePollutionUtility/tests.js | 16 ++- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected index 88fd5914d69..2a40a00d1ef 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected @@ -1042,6 +1042,54 @@ nodes | PrototypePollutionUtility/tests.js:461:24:461:28 | value | | PrototypePollutionUtility/tests.js:461:24:461:28 | value | | PrototypePollutionUtility/tests.js:461:24:461:28 | value | +| PrototypePollutionUtility/tests.js:467:26:467:28 | dst | +| PrototypePollutionUtility/tests.js:467:31:467:33 | src | +| PrototypePollutionUtility/tests.js:467:31:467:33 | src | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | +| PrototypePollutionUtility/tests.js:471:29:471:31 | dst | +| PrototypePollutionUtility/tests.js:471:29:471:36 | dst[key] | +| PrototypePollutionUtility/tests.js:471:29:471:36 | dst[key] | +| PrototypePollutionUtility/tests.js:471:33:471:35 | key | +| PrototypePollutionUtility/tests.js:471:39:471:41 | src | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | +| PrototypePollutionUtility/tests.js:471:43:471:45 | key | +| PrototypePollutionUtility/tests.js:473:13:473:15 | dst | +| PrototypePollutionUtility/tests.js:473:13:473:15 | dst | +| PrototypePollutionUtility/tests.js:473:17:473:19 | key | +| PrototypePollutionUtility/tests.js:473:17:473:19 | key | +| PrototypePollutionUtility/tests.js:473:24:473:26 | src | +| PrototypePollutionUtility/tests.js:473:24:473:26 | src | +| PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:28:473:30 | key | +| PrototypePollutionUtility/tests.js:478:32:478:34 | src | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:21:482:23 | src | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | +| PrototypePollutionUtility/tests.js:482:25:482:27 | key | +| PrototypePollutionUtility/tests.js:484:38:484:42 | value | +| PrototypePollutionUtility/tests.js:484:38:484:42 | value | +| PrototypePollutionUtility/tests.js:486:17:486:19 | key | +| PrototypePollutionUtility/tests.js:486:17:486:19 | key | +| PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:486:24:486:28 | value | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | | examples/PrototypePollutionUtility.js:1:21:1:23 | src | @@ -2457,6 +2505,64 @@ edges | PrototypePollutionUtility/tests.js:459:41:459:48 | dst[key] | PrototypePollutionUtility/tests.js:456:38:456:40 | dst | | PrototypePollutionUtility/tests.js:459:45:459:47 | key | PrototypePollutionUtility/tests.js:459:41:459:48 | dst[key] | | PrototypePollutionUtility/tests.js:459:45:459:47 | key | PrototypePollutionUtility/tests.js:459:41:459:48 | dst[key] | +| PrototypePollutionUtility/tests.js:467:26:467:28 | dst | PrototypePollutionUtility/tests.js:471:29:471:31 | dst | +| PrototypePollutionUtility/tests.js:467:26:467:28 | dst | PrototypePollutionUtility/tests.js:473:13:473:15 | dst | +| PrototypePollutionUtility/tests.js:467:26:467:28 | dst | PrototypePollutionUtility/tests.js:473:13:473:15 | dst | +| PrototypePollutionUtility/tests.js:467:31:467:33 | src | PrototypePollutionUtility/tests.js:471:39:471:41 | src | +| PrototypePollutionUtility/tests.js:467:31:467:33 | src | PrototypePollutionUtility/tests.js:473:24:473:26 | src | +| PrototypePollutionUtility/tests.js:467:31:467:33 | src | PrototypePollutionUtility/tests.js:473:24:473:26 | src | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:471:33:471:35 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:471:33:471:35 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:471:43:471:45 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:471:43:471:45 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:473:17:473:19 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:473:17:473:19 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:473:17:473:19 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:473:17:473:19 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:473:28:473:30 | key | +| PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:473:28:473:30 | key | +| PrototypePollutionUtility/tests.js:471:29:471:31 | dst | PrototypePollutionUtility/tests.js:471:29:471:36 | dst[key] | +| PrototypePollutionUtility/tests.js:471:29:471:36 | dst[key] | PrototypePollutionUtility/tests.js:467:26:467:28 | dst | +| PrototypePollutionUtility/tests.js:471:29:471:36 | dst[key] | PrototypePollutionUtility/tests.js:467:26:467:28 | dst | +| PrototypePollutionUtility/tests.js:471:33:471:35 | key | PrototypePollutionUtility/tests.js:471:29:471:36 | dst[key] | +| PrototypePollutionUtility/tests.js:471:39:471:41 | src | PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | PrototypePollutionUtility/tests.js:467:31:467:33 | src | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | PrototypePollutionUtility/tests.js:467:31:467:33 | src | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | PrototypePollutionUtility/tests.js:467:31:467:33 | src | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | PrototypePollutionUtility/tests.js:467:31:467:33 | src | +| PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | PrototypePollutionUtility/tests.js:467:31:467:33 | src | +| PrototypePollutionUtility/tests.js:471:43:471:45 | key | PrototypePollutionUtility/tests.js:471:39:471:46 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:26 | src | PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:26 | src | PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:26 | src | PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:26 | src | PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:28:473:30 | key | PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:473:28:473:30 | key | PrototypePollutionUtility/tests.js:473:24:473:31 | src[key] | +| PrototypePollutionUtility/tests.js:478:32:478:34 | src | PrototypePollutionUtility/tests.js:482:21:482:23 | src | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | PrototypePollutionUtility/tests.js:482:25:482:27 | key | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | PrototypePollutionUtility/tests.js:482:25:482:27 | key | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | PrototypePollutionUtility/tests.js:486:17:486:19 | key | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | PrototypePollutionUtility/tests.js:486:17:486:19 | key | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | PrototypePollutionUtility/tests.js:486:17:486:19 | key | +| PrototypePollutionUtility/tests.js:479:14:479:16 | key | PrototypePollutionUtility/tests.js:486:17:486:19 | key | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:484:38:484:42 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:484:38:484:42 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:482:13:482:28 | value | PrototypePollutionUtility/tests.js:486:24:486:28 | value | +| PrototypePollutionUtility/tests.js:482:21:482:23 | src | PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | PrototypePollutionUtility/tests.js:482:13:482:28 | value | +| PrototypePollutionUtility/tests.js:482:25:482:27 | key | PrototypePollutionUtility/tests.js:482:21:482:28 | src[key] | +| PrototypePollutionUtility/tests.js:484:38:484:42 | value | PrototypePollutionUtility/tests.js:478:32:478:34 | src | +| PrototypePollutionUtility/tests.js:484:38:484:42 | value | PrototypePollutionUtility/tests.js:478:32:478:34 | src | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | examples/PrototypePollutionUtility.js:5:19:5:21 | dst | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | examples/PrototypePollutionUtility.js:5:19:5:21 | dst | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | examples/PrototypePollutionUtility.js:7:13:7:15 | dst | @@ -2583,4 +2689,5 @@ edges | PrototypePollutionUtility/tests.js:450:30:450:32 | dst | PrototypePollutionUtility/tests.js:444:25:444:27 | key | PrototypePollutionUtility/tests.js:450:30:450:32 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:444:12:444:14 | src | src | PrototypePollutionUtility/tests.js:450:30:450:32 | dst | dst | | PrototypePollutionUtility/tests.js:451:30:451:32 | dst | PrototypePollutionUtility/tests.js:444:25:444:27 | key | PrototypePollutionUtility/tests.js:451:30:451:32 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:444:12:444:14 | src | src | PrototypePollutionUtility/tests.js:451:30:451:32 | dst | dst | | PrototypePollutionUtility/tests.js:461:13:461:15 | dst | PrototypePollutionUtility/tests.js:457:25:457:27 | key | PrototypePollutionUtility/tests.js:461:13:461:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:457:12:457:14 | src | src | PrototypePollutionUtility/tests.js:461:13:461:15 | dst | dst | +| PrototypePollutionUtility/tests.js:473:13:473:15 | dst | PrototypePollutionUtility/tests.js:468:14:468:16 | key | PrototypePollutionUtility/tests.js:473:13:473:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:468:21:468:23 | src | src | PrototypePollutionUtility/tests.js:473:13:473:15 | dst | dst | | examples/PrototypePollutionUtility.js:7:13:7:15 | dst | examples/PrototypePollutionUtility.js:2:14:2:16 | key | examples/PrototypePollutionUtility.js:7:13:7:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | examples/PrototypePollutionUtility.js:2:21:2:23 | src | src | examples/PrototypePollutionUtility.js:7:13:7:15 | dst | dst | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js index 0c929e75093..6bcfcefbadc 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js +++ b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js @@ -466,10 +466,24 @@ function copyUsingUnderscoreOrLodash(dst, src) { let isPlainObject = require('is-plain-object'); function copyPlainObject(dst, src) { for (let key in src) { + if (key === '__proto__') continue; if (dst[key] && isPlainObject(src)) { copyPlainObject(dst[key], src[key]); } else { - dst[key] = src[key]; // OK + dst[key] = src[key]; // OK - but flagged anyway + } + } +} + +function copyPlainObject2(dst, src) { + for (let key in src) { + if (key === '__proto__') continue; + let target = dst[key]; + let value = src[key]; + if (isPlainObject(target) && isPlainObject(value)) { + copyPlainObject2(target, value); + } else { + dst[key] = value; // OK } } } From 7f939fe1e41ff8d191ed2dbbd873457b2c69a9b4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 6 Feb 2020 11:32:10 +0000 Subject: [PATCH 098/134] TS: Update to TypeScript 3.8.2 --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index f1f82f91f25..55994647a94 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "3.7.5" + "typescript": "3.8.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 4562b05a011..5afdf469e36 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -225,9 +225,9 @@ tsutils@^2.12.1: dependencies: tslib "^1.8.1" -typescript@3.7.5: - version "3.7.5" - resolved "typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" +typescript@3.8.2: + version "3.8.2" + resolved typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a wrappy@1: version "1.0.2" From 9b52acc62ac167d606ac96055d8201548458792a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 6 Feb 2020 16:26:16 +0000 Subject: [PATCH 099/134] TS: Handle export * as ns --- .../js/parser/TypeScriptASTConverter.java | 18 +++++++++++++----- .../ExportNamespaceSpecifier/client.ts | 3 +++ .../TypeScript/ExportNamespaceSpecifier/lib.ts | 1 + .../ExportNamespaceSpecifier/reexport.ts | 1 + .../ExportNamespaceSpecifier/test.expected | 1 + .../ExportNamespaceSpecifier/test.ql | 3 +++ 6 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 1b0e5421497..c4dbf02aa3a 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -34,6 +34,7 @@ import com.semmle.js.ast.ExportAllDeclaration; import com.semmle.js.ast.ExportDeclaration; import com.semmle.js.ast.ExportDefaultDeclaration; import com.semmle.js.ast.ExportNamedDeclaration; +import com.semmle.js.ast.ExportNamespaceSpecifier; import com.semmle.js.ast.ExportSpecifier; import com.semmle.js.ast.Expression; import com.semmle.js.ast.ExpressionStatement; @@ -507,6 +508,8 @@ public class TypeScriptASTConverter { return convertNamespaceDeclaration(node, loc); case "ModuleBlock": return convertModuleBlock(node, loc); + case "NamespaceExport": + return convertNamespaceExport(node, loc); case "NamespaceExportDeclaration": return convertNamespaceExportDeclaration(node, loc); case "NamespaceImport": @@ -1170,11 +1173,11 @@ public class TypeScriptASTConverter { private Node convertExportDeclaration(JsonObject node, SourceLocation loc) throws ParseError { Literal source = tryConvertChild(node, "moduleSpecifier", Literal.class); if (hasChild(node, "exportClause")) { - return new ExportNamedDeclaration( - loc, - null, - convertChildren(node.get("exportClause").getAsJsonObject(), "elements"), - source); + List specifiers = + hasKind(node.get("exportClause"), "NamespaceExport") + ? Collections.singletonList(convertChild(node, "exportClause")) + : convertChildren(node.get("exportClause").getAsJsonObject(), "elements"); + return new ExportNamedDeclaration(loc, null, specifiers, source); } else { return new ExportAllDeclaration(loc, source); } @@ -1187,6 +1190,11 @@ public class TypeScriptASTConverter { convertChild(node, "name")); } + private Node convertNamespaceExport(JsonObject node, SourceLocation loc) throws ParseError { + // Convert the "* as ns" from an export declaration. + return new ExportNamespaceSpecifier(loc, convertChild(node, "name")); + } + private Node convertExpressionStatement(JsonObject node, SourceLocation loc) throws ParseError { Expression expression = convertChild(node, "expression"); return new ExpressionStatement(loc, expression); diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts new file mode 100644 index 00000000000..b4004f7005b --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/client.ts @@ -0,0 +1,3 @@ +import { ns } from "./reexport"; + +ns.foo(); diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts new file mode 100644 index 00000000000..f99d4277774 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/lib.ts @@ -0,0 +1 @@ +export function foo() {} diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts new file mode 100644 index 00000000000..19c4b621498 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/reexport.ts @@ -0,0 +1 @@ +export * as ns from "./lib"; diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected new file mode 100644 index 00000000000..6403f1793a4 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected @@ -0,0 +1 @@ +| reexport.ts:1:13:1:14 | ns | diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql new file mode 100644 index 00000000000..44f3f9d7fd4 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.ql @@ -0,0 +1,3 @@ +import javascript + +query ExportNamespaceSpecifier test_ExportNamespaceSpecifier() { any() } From 8531c113a1982d245e23b2f2eca0065e37152e12 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 6 Feb 2020 16:48:19 +0000 Subject: [PATCH 100/134] TS: Fix imports --- .../semmle/js/parser/TypeScriptASTConverter.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index c4dbf02aa3a..b6bd5041a48 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -1,5 +1,13 @@ package com.semmle.js.parser; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -145,13 +153,6 @@ import com.semmle.ts.ast.UnaryTypeExpr; import com.semmle.ts.ast.UnionTypeExpr; import com.semmle.util.collections.CollectionUtil; import com.semmle.util.data.IntList; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Utility class for converting a Date: Thu, 6 Feb 2020 16:49:40 +0000 Subject: [PATCH 101/134] TS: Add test and documentation for private fields --- .../js/parser/TypeScriptASTConverter.java | 7 +- .../extractor/tests/ts/input/privateField.ts | 6 + .../tests/ts/output/trap/privateField.ts.trap | 273 ++++++++++++++++++ .../TypeScript/PrivateFields/test.expected | 5 + .../TypeScript/PrivateFields/test.ql | 9 + .../TypeScript/PrivateFields/tst.ts | 8 + 6 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 javascript/extractor/tests/ts/input/privateField.ts create mode 100644 javascript/extractor/tests/ts/output/trap/privateField.ts.trap create mode 100644 javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index b6bd5041a48..8299abebe8b 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -336,7 +336,11 @@ public class TypeScriptASTConverter { private Node convertNodeUntyped(JsonObject node, String defaultKind) throws ParseError { String kind = getKind(node); if (kind == null) kind = defaultKind; - if (kind == null) kind = "Identifier"; + if (kind == null) { + // Identifiers and PrivateIdentifiers do not have a "kind" property like other nodes. + // Since we encode identifiers and private identifiers the same, default to Identifier. + kind = "Identifier"; + } SourceLocation loc = getSourceLocation(node); switch (kind) { case "AnyKeyword": @@ -443,6 +447,7 @@ public class TypeScriptASTConverter { case "FunctionType": return convertFunctionType(node, loc); case "Identifier": + case "PrivateIdentifier": return convertIdentifier(node, loc); case "IfStatement": return convertIfStatement(node, loc); diff --git a/javascript/extractor/tests/ts/input/privateField.ts b/javascript/extractor/tests/ts/input/privateField.ts new file mode 100644 index 00000000000..a6cd745260c --- /dev/null +++ b/javascript/extractor/tests/ts/input/privateField.ts @@ -0,0 +1,6 @@ +class C { + #foo; + constructor() { + this.#foo = 5; + } +} diff --git a/javascript/extractor/tests/ts/output/trap/privateField.ts.trap b/javascript/extractor/tests/ts/output/trap/privateField.ts.trap new file mode 100644 index 00000000000..97567d63457 --- /dev/null +++ b/javascript/extractor/tests/ts/output/trap/privateField.ts.trap @@ -0,0 +1,273 @@ +#10000=@"/privateField.ts;sourcefile" +files(#10000,"/privateField.ts","privateField","ts",0) +#10001=@"/;folder" +folders(#10001,"/","") +containerparent(#10001,#10000) +#10002=@"loc,{#10000},0,0,0,0" +locations_default(#10002,#10000,0,0,0,0) +hasLocation(#10000,#10002) +#20000=@"global_scope" +scopes(#20000,0) +#20001=@"script;{#10000},1,1" +#20002=* +lines(#20002,#20001,"class C {"," +") +#20003=@"loc,{#10000},1,1,1,9" +locations_default(#20003,#10000,1,1,1,9) +hasLocation(#20002,#20003) +#20004=* +lines(#20004,#20001," #foo;"," +") +#20005=@"loc,{#10000},2,1,2,6" +locations_default(#20005,#10000,2,1,2,6) +hasLocation(#20004,#20005) +indentation(#10000,2," ",1) +#20006=* +lines(#20006,#20001," constructor() {"," +") +#20007=@"loc,{#10000},3,1,3,16" +locations_default(#20007,#10000,3,1,3,16) +hasLocation(#20006,#20007) +indentation(#10000,3," ",1) +#20008=* +lines(#20008,#20001," this.#foo = 5;"," +") +#20009=@"loc,{#10000},4,1,4,17" +locations_default(#20009,#10000,4,1,4,17) +hasLocation(#20008,#20009) +indentation(#10000,4," ",3) +#20010=* +lines(#20010,#20001," }"," +") +#20011=@"loc,{#10000},5,1,5,2" +locations_default(#20011,#10000,5,1,5,2) +hasLocation(#20010,#20011) +indentation(#10000,5," ",1) +#20012=* +lines(#20012,#20001,"}"," +") +#20013=@"loc,{#10000},6,1,6,1" +locations_default(#20013,#10000,6,1,6,1) +hasLocation(#20012,#20013) +numlines(#20001,6,6,0) +#20014=* +tokeninfo(#20014,7,#20001,0,"class") +#20015=@"loc,{#10000},1,1,1,5" +locations_default(#20015,#10000,1,1,1,5) +hasLocation(#20014,#20015) +#20016=* +tokeninfo(#20016,6,#20001,1,"C") +#20017=@"loc,{#10000},1,7,1,7" +locations_default(#20017,#10000,1,7,1,7) +hasLocation(#20016,#20017) +#20018=* +tokeninfo(#20018,8,#20001,2,"{") +#20019=@"loc,{#10000},1,9,1,9" +locations_default(#20019,#10000,1,9,1,9) +hasLocation(#20018,#20019) +#20020=* +tokeninfo(#20020,8,#20001,3,";") +#20021=@"loc,{#10000},2,6,2,6" +locations_default(#20021,#10000,2,6,2,6) +hasLocation(#20020,#20021) +#20022=* +tokeninfo(#20022,7,#20001,4,"constructor") +#20023=@"loc,{#10000},3,2,3,12" +locations_default(#20023,#10000,3,2,3,12) +hasLocation(#20022,#20023) +#20024=* +tokeninfo(#20024,8,#20001,5,"(") +#20025=@"loc,{#10000},3,13,3,13" +locations_default(#20025,#10000,3,13,3,13) +hasLocation(#20024,#20025) +#20026=* +tokeninfo(#20026,8,#20001,6,")") +#20027=@"loc,{#10000},3,14,3,14" +locations_default(#20027,#10000,3,14,3,14) +hasLocation(#20026,#20027) +#20028=* +tokeninfo(#20028,8,#20001,7,"{") +#20029=@"loc,{#10000},3,16,3,16" +locations_default(#20029,#10000,3,16,3,16) +hasLocation(#20028,#20029) +#20030=* +tokeninfo(#20030,7,#20001,8,"this") +#20031=@"loc,{#10000},4,4,4,7" +locations_default(#20031,#10000,4,4,4,7) +hasLocation(#20030,#20031) +#20032=* +tokeninfo(#20032,8,#20001,9,".") +#20033=@"loc,{#10000},4,8,4,8" +locations_default(#20033,#10000,4,8,4,8) +hasLocation(#20032,#20033) +#20034=* +tokeninfo(#20034,8,#20001,10,"=") +#20035=@"loc,{#10000},4,14,4,14" +locations_default(#20035,#10000,4,14,4,14) +hasLocation(#20034,#20035) +#20036=* +tokeninfo(#20036,3,#20001,11,"5") +#20037=@"loc,{#10000},4,16,4,16" +locations_default(#20037,#10000,4,16,4,16) +hasLocation(#20036,#20037) +#20038=* +tokeninfo(#20038,8,#20001,12,";") +#20039=@"loc,{#10000},4,17,4,17" +locations_default(#20039,#10000,4,17,4,17) +hasLocation(#20038,#20039) +#20040=* +tokeninfo(#20040,8,#20001,13,"}") +#20041=@"loc,{#10000},5,2,5,2" +locations_default(#20041,#10000,5,2,5,2) +hasLocation(#20040,#20041) +#20042=* +tokeninfo(#20042,8,#20001,14,"}") +hasLocation(#20042,#20013) +#20043=* +tokeninfo(#20043,0,#20001,15,"") +#20044=@"loc,{#10000},7,1,7,0" +locations_default(#20044,#10000,7,1,7,0) +hasLocation(#20043,#20044) +toplevels(#20001,0) +#20045=@"loc,{#10000},1,1,7,0" +locations_default(#20045,#10000,1,1,7,0) +hasLocation(#20001,#20045) +#20046=@"var;{C};{#20000}" +variables(#20046,"C",#20000) +#20047=@"local_type_name;{C};{#20000}" +local_type_names(#20047,"C",#20000) +#20048=* +stmts(#20048,26,#20001,0,"class C ... 5;\n }\n}") +#20049=@"loc,{#10000},1,1,6,1" +locations_default(#20049,#10000,1,1,6,1) +hasLocation(#20048,#20049) +stmtContainers(#20048,#20001) +#20050=* +exprs(#20050,78,#20048,0,"C") +hasLocation(#20050,#20017) +enclosingStmt(#20050,#20048) +exprContainers(#20050,#20001) +literals("C","C",#20050) +decl(#20050,#20046) +typedecl(#20050,#20047) +#20051=* +scopes(#20051,10) +scopenodes(#20048,#20051) +scopenesting(#20051,#20000) +#20052=* +properties(#20052,#20048,2,8,"#foo;") +#20053=@"loc,{#10000},2,2,2,6" +locations_default(#20053,#10000,2,2,2,6) +hasLocation(#20052,#20053) +#20054=* +#20055=* +exprs(#20055,0,#20052,0,"#foo") +#20056=@"loc,{#10000},2,2,2,5" +locations_default(#20056,#10000,2,2,2,5) +hasLocation(#20055,#20056) +exprContainers(#20055,#20054) +literals("#foo","#foo",#20055) +#20057=* +properties(#20057,#20048,3,0,"constru ... = 5;\n }") +#20058=@"loc,{#10000},3,2,5,2" +locations_default(#20058,#10000,3,2,5,2) +hasLocation(#20057,#20058) +#20059=* +exprs(#20059,0,#20057,0,"constru ... = 5;\n }") +hasLocation(#20059,#20058) +enclosingStmt(#20059,#20048) +exprContainers(#20059,#20001) +literals("constructor","constructor",#20059) +exprs(#20054,9,#20057,1,"constru ... = 5;\n }") +hasLocation(#20054,#20058) +enclosingStmt(#20054,#20048) +exprContainers(#20054,#20001) +#20060=* +scopes(#20060,1) +scopenodes(#20054,#20060) +scopenesting(#20060,#20051) +#20061=@"var;{arguments};{#20060}" +variables(#20061,"arguments",#20060) +isArgumentsObject(#20061) +#20062=* +stmts(#20062,1,#20054,-2,"{\n th ... = 5;\n }") +#20063=@"loc,{#10000},3,16,5,2" +locations_default(#20063,#10000,3,16,5,2) +hasLocation(#20062,#20063) +stmtContainers(#20062,#20054) +#20064=* +stmts(#20064,2,#20062,0,"this.#foo = 5;") +#20065=@"loc,{#10000},4,4,4,17" +locations_default(#20065,#10000,4,4,4,17) +hasLocation(#20064,#20065) +stmtContainers(#20064,#20054) +#20066=* +exprs(#20066,47,#20064,0,"this.#foo = 5") +#20067=@"loc,{#10000},4,4,4,16" +locations_default(#20067,#10000,4,4,4,16) +hasLocation(#20066,#20067) +enclosingStmt(#20066,#20064) +exprContainers(#20066,#20054) +#20068=* +exprs(#20068,14,#20066,0,"this.#foo") +#20069=@"loc,{#10000},4,4,4,12" +locations_default(#20069,#10000,4,4,4,12) +hasLocation(#20068,#20069) +enclosingStmt(#20068,#20064) +exprContainers(#20068,#20054) +#20070=* +exprs(#20070,6,#20068,0,"this") +hasLocation(#20070,#20031) +enclosingStmt(#20070,#20064) +exprContainers(#20070,#20054) +#20071=* +exprs(#20071,0,#20068,1,"#foo") +#20072=@"loc,{#10000},4,9,4,12" +locations_default(#20072,#10000,4,9,4,12) +hasLocation(#20071,#20072) +enclosingStmt(#20071,#20064) +exprContainers(#20071,#20054) +literals("#foo","#foo",#20071) +#20073=* +exprs(#20073,3,#20066,1,"5") +hasLocation(#20073,#20037) +enclosingStmt(#20073,#20064) +exprContainers(#20073,#20054) +literals("5","5",#20073) +isMethod(#20057) +#20074=* +entry_cfg_node(#20074,#20001) +#20075=@"loc,{#10000},1,1,1,0" +locations_default(#20075,#10000,1,1,1,0) +hasLocation(#20074,#20075) +#20076=* +exit_cfg_node(#20076,#20001) +hasLocation(#20076,#20044) +successor(#20055,#20052) +successor(#20054,#20057) +#20077=* +entry_cfg_node(#20077,#20054) +#20078=@"loc,{#10000},3,2,3,1" +locations_default(#20078,#10000,3,2,3,1) +hasLocation(#20077,#20078) +successor(#20052,#20062) +#20079=* +exit_cfg_node(#20079,#20054) +#20080=@"loc,{#10000},5,3,5,2" +locations_default(#20080,#10000,5,3,5,2) +hasLocation(#20079,#20080) +successor(#20062,#20064) +successor(#20064,#20070) +successor(#20073,#20066) +successor(#20071,#20068) +successor(#20070,#20071) +successor(#20068,#20073) +successor(#20066,#20079) +successor(#20077,#20055) +successor(#20059,#20054) +successor(#20057,#20048) +successor(#20050,#20059) +successor(#20048,#20076) +successor(#20074,#20050) +numlines(#10000,6,6,0) +filetype(#10000,"typescript") diff --git a/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected new file mode 100644 index 00000000000..fc28ada4ff9 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.expected @@ -0,0 +1,5 @@ +propAccess +| #privateField | tst.ts:5:9:5:26 | this.#privateField | +| #privateField | tst.ts:6:9:6:26 | this.#privateField | +fieldDecl +| #privateField | tst.ts:2:5:2:23 | #privateField: any; | diff --git a/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql new file mode 100644 index 00000000000..27147fcb461 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/PrivateFields/test.ql @@ -0,0 +1,9 @@ +import javascript + +query PropAccess propAccess(string name) { + result.getPropertyName() = name +} + +query FieldDeclaration fieldDecl(string name) { + result.getName() = name +} diff --git a/javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts b/javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts new file mode 100644 index 00000000000..9e2dbdca644 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/PrivateFields/tst.ts @@ -0,0 +1,8 @@ +class C { + #privateField: any; + + constructor(x: any) { + this.#privateField = x; + this.#privateField(y); + } +} From 8d58aad0f2b389f6e3e6be20e7013ea2e20d3dbc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 16:25:49 +0000 Subject: [PATCH 102/134] TS: Support type-only import/export --- .../semmle/js/ast/ExportNamedDeclaration.java | 13 ++++++ .../com/semmle/js/ast/ImportDeclaration.java | 15 ++++++- .../com/semmle/js/extractor/ASTExtractor.java | 44 +++++++++++++++++-- .../com/semmle/js/extractor/ExprKinds.java | 9 ++-- .../js/parser/TypeScriptASTConverter.java | 7 ++- javascript/ql/src/semmle/javascript/AST.qll | 2 +- .../src/semmle/javascript/ES2015Modules.qll | 32 ++++++++++++++ .../ql/src/semmlecode.javascript.dbscheme | 3 ++ .../TypeOnlyImportExport/test.expected | 6 +++ .../TypeScript/TypeOnlyImportExport/test.ql | 13 ++++++ .../TypeScript/TypeOnlyImportExport/tst.ts | 5 +++ 11 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts diff --git a/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java b/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java index c70ed56b30a..d4d19b8d1ab 100644 --- a/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java +++ b/javascript/extractor/src/com/semmle/js/ast/ExportNamedDeclaration.java @@ -15,13 +15,21 @@ public class ExportNamedDeclaration extends ExportDeclaration { private final Statement declaration; private final List specifiers; private final Literal source; + private final boolean hasTypeKeyword; public ExportNamedDeclaration( SourceLocation loc, Statement declaration, List specifiers, Literal source) { + this(loc, declaration, specifiers, source, false); + } + + public ExportNamedDeclaration( + SourceLocation loc, Statement declaration, List specifiers, Literal source, + boolean hasTypeKeyword) { super("ExportNamedDeclaration", loc); this.declaration = declaration; this.specifiers = specifiers; this.source = source; + this.hasTypeKeyword = hasTypeKeyword; } public Statement getDeclaration() { @@ -48,4 +56,9 @@ public class ExportNamedDeclaration extends ExportDeclaration { public R accept(Visitor v, C c) { return v.visit(this, c); } + + /** Returns true if this is an export type declaration. */ + public boolean hasTypeKeyword() { + return hasTypeKeyword; + } } diff --git a/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java b/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java index 1e538c1bb74..8a291000f2f 100644 --- a/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java +++ b/javascript/extractor/src/com/semmle/js/ast/ImportDeclaration.java @@ -1,8 +1,9 @@ package com.semmle.js.ast; -import com.semmle.ts.ast.INodeWithSymbol; import java.util.List; +import com.semmle.ts.ast.INodeWithSymbol; + /** * An import declaration, which can be of one of the following forms: * @@ -24,10 +25,17 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol { private int symbol = -1; + private boolean hasTypeKeyword; + public ImportDeclaration(SourceLocation loc, List specifiers, Literal source) { + this(loc, specifiers, source, false); + } + + public ImportDeclaration(SourceLocation loc, List specifiers, Literal source, boolean hasTypeKeyword) { super("ImportDeclaration", loc); this.specifiers = specifiers; this.source = source; + this.hasTypeKeyword = hasTypeKeyword; } public Literal getSource() { @@ -52,4 +60,9 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol { public void setSymbol(int symbol) { this.symbol = symbol; } + + /** Returns true if this is an import type declaration. */ + public boolean hasTypeKeyword() { + return hasTypeKeyword; + } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 6af90d562d8..19b3283121d 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -250,6 +250,22 @@ public class ASTExtractor { /** An identifier that declares a variable and a namespace. */ varAndNamespaceDecl, + /** + * An identifier that occurs in a type-only import. + * + * These may declare a type and/or a namespace, but for compatibility with our AST, + * must be emitted as a VarDecl (with no variable binding). + */ + typeOnlyImport, + + /** + * An identifier that occurs in a type-only export. + * + * These may refer to a type and/or a namespace, but for compatibility with our AST, + * must be emitted as an ExportVarAccess (with no variable binding). + */ + typeOnlyExport, + /** An identifier that declares a variable, type, and namepsace. */ varAndTypeAndNamespaceDecl, @@ -278,7 +294,8 @@ public class ASTExtractor { * True if this occurs as part of a type annotation, i.e. it is {@link #typeBind} or {@link * #typeDecl}, {@link #typeLabel}, {@link #varInTypeBind}, or {@link #namespaceBind}. * - *

Does not hold for {@link #varAndTypeDecl}. + *

Does not hold for {@link #varAndTypeDecl} or {@link #typeOnlyImportExport} as these + * do not occur in type annotations. */ public boolean isInsideType() { return this == typeBind @@ -488,6 +505,14 @@ public class ASTExtractor { addVariableBinding("decl", key, name); addNamespaceBinding("namespacedecl", key, name); break; + case typeOnlyImport: + addTypeBinding("typedecl", key, name); + addNamespaceBinding("namespacedecl", key, name); + break; + case typeOnlyExport: + addTypeBinding("typebind", key, name); + addNamespaceBinding("namespacebind", key, name); + break; case varAndTypeAndNamespaceDecl: addVariableBinding("decl", key, name); addTypeBinding("typedecl", key, name); @@ -1538,7 +1563,14 @@ public class ASTExtractor { Label lbl = super.visit(nd, c); visit(nd.getDeclaration(), lbl, -1); visit(nd.getSource(), lbl, -2); - visitAll(nd.getSpecifiers(), lbl, nd.hasSource() ? IdContext.label : IdContext.export, 0); + IdContext childContext = + nd.hasSource() ? IdContext.label : + nd.hasTypeKeyword() ? IdContext.typeOnlyExport : + IdContext.export; + visitAll(nd.getSpecifiers(), lbl, childContext, 0); + if (nd.hasTypeKeyword()) { + trapwriter.addTuple("hasTypeKeyword", lbl); + } return lbl; } @@ -1554,8 +1586,12 @@ public class ASTExtractor { public Label visit(ImportDeclaration nd, Context c) { Label lbl = super.visit(nd, c); visit(nd.getSource(), lbl, -1); - visitAll(nd.getSpecifiers(), lbl); + IdContext childContext = nd.hasTypeKeyword() ? IdContext.typeOnlyImport : IdContext.varAndTypeAndNamespaceDecl; + visitAll(nd.getSpecifiers(), lbl, childContext, 0); emitNodeSymbol(nd, lbl); + if (nd.hasTypeKeyword()) { + trapwriter.addTuple("hasTypeKeyword", lbl); + } return lbl; } @@ -1563,7 +1599,7 @@ public class ASTExtractor { public Label visit(ImportSpecifier nd, Context c) { Label lbl = super.visit(nd, c); visit(nd.getImported(), lbl, 0, IdContext.label); - visit(nd.getLocal(), lbl, 1, IdContext.varAndTypeAndNamespaceDecl); + visit(nd.getLocal(), lbl, 1, c.idcontext); return lbl; } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java b/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java index 122ccda028e..d88f341bc0e 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java @@ -1,5 +1,9 @@ package com.semmle.js.extractor; +import java.util.EnumMap; +import java.util.LinkedHashMap; +import java.util.Map; + import com.semmle.jcorn.TokenType; import com.semmle.jcorn.jsx.JSXParser; import com.semmle.js.ast.AssignmentExpression; @@ -29,9 +33,6 @@ import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.ExpressionWithTypeArguments; import com.semmle.ts.ast.TypeAssertion; import com.semmle.util.exception.CatastrophicError; -import java.util.EnumMap; -import java.util.LinkedHashMap; -import java.util.Map; /** Map from SpiderMonkey expression types to the numeric kinds used in the DB scheme. */ public class ExprKinds { @@ -154,6 +155,8 @@ public class ExprKinds { idKinds.put(IdContext.namespaceDecl, 78); idKinds.put(IdContext.varAndNamespaceDecl, 78); idKinds.put(IdContext.varAndTypeAndNamespaceDecl, 78); + idKinds.put(IdContext.typeOnlyImport, 78); + idKinds.put(IdContext.typeOnlyExport, 103); idKinds.put(IdContext.varBind, 79); idKinds.put(IdContext.export, 103); idKinds.put(IdContext.exportBase, 103); diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 8299abebe8b..0643cc15ef5 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -1179,11 +1179,12 @@ public class TypeScriptASTConverter { private Node convertExportDeclaration(JsonObject node, SourceLocation loc) throws ParseError { Literal source = tryConvertChild(node, "moduleSpecifier", Literal.class); if (hasChild(node, "exportClause")) { + boolean hasTypeKeyword = node.get("isTypeOnly").getAsBoolean(); List specifiers = hasKind(node.get("exportClause"), "NamespaceExport") ? Collections.singletonList(convertChild(node, "exportClause")) : convertChildren(node.get("exportClause").getAsJsonObject(), "elements"); - return new ExportNamedDeclaration(loc, null, specifiers, source); + return new ExportNamedDeclaration(loc, null, specifiers, source, hasTypeKeyword); } else { return new ExportAllDeclaration(loc, source); } @@ -1368,6 +1369,7 @@ public class TypeScriptASTConverter { private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throws ParseError { Literal src = tryConvertChild(node, "moduleSpecifier", Literal.class); List specifiers = new ArrayList<>(); + boolean hasTypeKeyword = false; if (hasChild(node, "importClause")) { JsonObject importClause = node.get("importClause").getAsJsonObject(); if (hasChild(importClause, "name")) { @@ -1381,8 +1383,9 @@ public class TypeScriptASTConverter { specifiers.addAll(convertChildren(namedBindings, "elements")); } } + hasTypeKeyword = importClause.get("isTypeOnly").getAsBoolean(); } - ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src); + ImportDeclaration importDecl = new ImportDeclaration(loc, specifiers, src, hasTypeKeyword); attachSymbolInformation(importDecl, node); return importDecl; } diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index 66a5155458c..b1cbe224764 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -125,7 +125,7 @@ class ASTNode extends @ast_node, Locatable { * Holds if this is part of an ambient declaration or type annotation in a TypeScript file. * * A declaration is ambient if it occurs under a `declare` modifier or is - * an interface declaration, type alias, or type annotation. + * an interface declaration, type alias, type annotation, or type-only import/export declaration. * * The TypeScript compiler emits no code for ambient declarations, but they * can affect name resolution and type checking at compile-time. diff --git a/javascript/ql/src/semmle/javascript/ES2015Modules.qll b/javascript/ql/src/semmle/javascript/ES2015Modules.qll index f75f582d851..ca50b3cdcc6 100644 --- a/javascript/ql/src/semmle/javascript/ES2015Modules.qll +++ b/javascript/ql/src/semmle/javascript/ES2015Modules.qll @@ -76,6 +76,16 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration { // `import { createServer } from 'http'` result = DataFlow::destructuredModuleImportNode(this) } + + /** Holds if this is declared with the `type` keyword, so it only imports types. */ + predicate isTypeOnly() { + hasTypeKeyword(this) + } + + override predicate isAmbient() { + Stmt.super.isAmbient() or + isTypeOnly() + } } /** A literal path expression appearing in an `import` declaration. */ @@ -256,6 +266,16 @@ abstract class ExportDeclaration extends Stmt, @exportdeclaration { * to module `a` or possibly to some other module from which `a` re-exports. */ abstract DataFlow::Node getSourceNode(string name); + + /** Holds if is declared with the `type` keyword, so only types are exported. */ + predicate isTypeOnly() { + hasTypeKeyword(this) + } + + override predicate isAmbient() { + Stmt.super.isAmbient() or + isTypeOnly() + } } /** @@ -413,6 +433,18 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration } } +/** + * An export declaration with the `type` modifier. + */ +private class TypeOnlyExportDeclaration extends ExportNamedDeclaration { + TypeOnlyExportDeclaration() { isTypeOnly() } + + override predicate exportsAs(LexicalName v, string name) { + super.exportsAs(v, name) and + not v instanceof Variable + } +} + /** * An export specifier in an export declaration. * diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index dad09eeeff5..03c078a7e6e 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -385,6 +385,8 @@ case @expr.kind of @exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + @typeassertion = @astypeassertion | @prefixtypeassertion; @classdefinition = @classdeclstmt | @classexpr; @@ -518,6 +520,7 @@ hasPublicKeyword (int id: @property ref); hasPrivateKeyword (int id: @property ref); hasProtectedKeyword (int id: @property ref); hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); isOptionalMember (int id: @property ref); hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); isOptionalParameterDeclaration (unique int parameter: @pattern ref); diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected new file mode 100644 index 00000000000..1127959be64 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -0,0 +1,6 @@ +getAVarReference +| Foo | tst.ts:5:5:5:7 | Foo | +getAnExportAccess +| Foo | tst.ts:3:15:3:17 | Foo | +getATypeDecl +| Foo | tst.ts:1:15:1:17 | Foo | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql new file mode 100644 index 00000000000..42d0acf7495 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql @@ -0,0 +1,13 @@ +import javascript + +query VarRef getAVarReference(Variable v) { + result = v.getAReference() +} + +query VarRef getAnExportAccess(LocalTypeName t) { + result = t.getAnExportAccess() +} + +query TypeDecl getATypeDecl(LocalTypeName t) { + result = t.getADeclaration() +} diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts new file mode 100644 index 00000000000..cb80e400923 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts @@ -0,0 +1,5 @@ +import type { Foo } from "foo"; + +export type { Foo }; + +var Foo = 45; From 260b243c2830db4fa416ef8fdbcde8f11e3915a4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 16:32:11 +0000 Subject: [PATCH 103/134] TS: Add test case to DeclBeforeUse --- .../query-tests/Declarations/DeclBeforeUse/typescript.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts b/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts index 18862ea5f5e..0de18d48a48 100644 --- a/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts +++ b/javascript/ql/test/query-tests/Declarations/DeclBeforeUse/typescript.ts @@ -3,3 +3,9 @@ class Foo {} declare class Bar extends Baz {} // OK declare class Baz {} + +export type { I }; // OK - does not refer to the constant 'I' + +const I = 45; + +interface I {} From 16c909b433ae15b37dacecbb18b03c354a0eddd4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 16:48:16 +0000 Subject: [PATCH 104/134] TS: Add test case for import type * as ns --- .../TypeScript/TypeOnlyImportExport/test.expected | 1 + .../test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected index 1127959be64..9ff9937769f 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -4,3 +4,4 @@ getAnExportAccess | Foo | tst.ts:3:15:3:17 | Foo | getATypeDecl | Foo | tst.ts:1:15:1:17 | Foo | +| types | tst.ts:7:18:7:22 | types | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts index cb80e400923..440e77b9dbc 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/tst.ts @@ -3,3 +3,7 @@ import type { Foo } from "foo"; export type { Foo }; var Foo = 45; + +import type * as types from "types"; + +export type * as blah from "blah"; From 47673c6e21c895012d6c76b65174ec1df129f1d8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 7 Feb 2020 17:13:47 +0000 Subject: [PATCH 105/134] TS: Disable export analysis for type-only exports --- .../dataflow/internal/InterModuleTypeInference.qll | 8 +++++++- .../TypeScript/TypeOnlyImportExport/exportFunction.ts | 1 + .../TypeScript/TypeOnlyImportExport/importFunction.ts | 3 +++ .../TypeScript/TypeOnlyImportExport/importType.ts | 3 +++ .../TypeScript/TypeOnlyImportExport/test.expected | 7 +++++++ .../library-tests/TypeScript/TypeOnlyImportExport/test.ql | 4 ++++ 6 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll index 6bc0eac95bc..4d60fdebcfd 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll @@ -405,10 +405,16 @@ private class AnalyzedClosureGlobalAccessPath extends AnalyzedNode, AnalyzedProp */ private class AnalyzedExportNamespaceSpecifier extends AnalyzedPropertyWrite, DataFlow::ValueNode { override ExportNamespaceSpecifier astNode; + ReExportDeclaration decl; + + AnalyzedExportNamespaceSpecifier() { + decl = astNode.getExportDeclaration() and + not decl.isTypeOnly() + } override predicate writesValue(AbstractValue baseVal, string propName, AbstractValue value) { baseVal = TAbstractExportsObject(getTopLevel()) and propName = astNode.getExportedName() and - value = TAbstractExportsObject(astNode.getExportDeclaration().(ReExportDeclaration).getReExportedModule()) + value = TAbstractExportsObject(decl.getReExportedModule()) } } diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts new file mode 100644 index 00000000000..8b38a11158b --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportFunction.ts @@ -0,0 +1 @@ +export function f() {} diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts new file mode 100644 index 00000000000..1034558749c --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importFunction.ts @@ -0,0 +1,3 @@ +import { ns } from "./importType"; + +ns.f(); // Calls local method in 'importType' diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts new file mode 100644 index 00000000000..090e94bc597 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importType.ts @@ -0,0 +1,3 @@ +export type * as ns from "./exportFunction"; + +export var ns = { f() {} }; diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected index 9ff9937769f..f4861fcc5ce 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -1,7 +1,14 @@ getAVarReference | Foo | tst.ts:5:5:5:7 | Foo | +| f | exportFunction.ts:1:17:1:17 | f | +| ns | importFunction.ts:1:10:1:11 | ns | +| ns | importFunction.ts:3:1:3:2 | ns | +| ns | importType.ts:3:12:3:13 | ns | getAnExportAccess | Foo | tst.ts:3:15:3:17 | Foo | getATypeDecl | Foo | tst.ts:1:15:1:17 | Foo | +| ns | importFunction.ts:1:10:1:11 | ns | | types | tst.ts:7:18:7:22 | types | +calls +| importFunction.ts:3:1:3:6 | ns.f() | importType.ts:3:19:3:24 | f() {} | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql index 42d0acf7495..3c3b9bf2320 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql @@ -11,3 +11,7 @@ query VarRef getAnExportAccess(LocalTypeName t) { query TypeDecl getATypeDecl(LocalTypeName t) { result = t.getADeclaration() } + +query Function calls(DataFlow::InvokeNode invoke) { + result = invoke.getACallee() +} From 18974bad1c0c6209e30f413509aae5d7e14bda6e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 10:28:59 +0000 Subject: [PATCH 106/134] TS: Add upgrade script and stats --- .../src/semmlecode.javascript.dbscheme.stats | 11 + .../old.dbscheme | 1186 ++++++++++++++++ .../semmlecode.javascript.dbscheme | 1189 +++++++++++++++++ .../upgrade.properties | 2 + 4 files changed, 2388 insertions(+) create mode 100644 javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme create mode 100644 javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme.stats b/javascript/ql/src/semmlecode.javascript.dbscheme.stats index 1bc81f76f9b..7e352454e59 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/src/semmlecode.javascript.dbscheme.stats @@ -7984,6 +7984,17 @@ +hasTypeKeyword +1000 + + +id +1000 + + + + + isOptionalMember 3668 diff --git a/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme new file mode 100644 index 00000000000..dad09eeeff5 --- /dev/null +++ b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/old.dbscheme @@ -0,0 +1,1186 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..03c078a7e6e --- /dev/null +++ b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/semmlecode.javascript.dbscheme @@ -0,0 +1,1189 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties new file mode 100644 index 00000000000..d0a417d20a6 --- /dev/null +++ b/javascript/upgrades/dad09eeeff5cf8c9c2b674d5053c63ab44e091df/upgrade.properties @@ -0,0 +1,2 @@ +description: add support for TypeScript 3.8 +compatibility: backwards From 05d9e64dab5081a939d7b25f6fa2f9d11e8146c0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 11:59:29 +0000 Subject: [PATCH 107/134] TS: Add change note --- change-notes/1.24/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 58c1698d799..50197d6f5a1 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -2,6 +2,8 @@ ## General improvements +* TypeScript 3.8 is now supported. + * Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). * Imports with the `.js` extension can now be resolved to a TypeScript file, From 4e1bd9056ce100741b080b89ffd5bd9f48b66dac Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 12:41:35 +0000 Subject: [PATCH 108/134] TS: Fix javadoc --- .../extractor/src/com/semmle/js/extractor/ASTExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 19b3283121d..8dcc6d3a5c5 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -294,8 +294,8 @@ public class ASTExtractor { * True if this occurs as part of a type annotation, i.e. it is {@link #typeBind} or {@link * #typeDecl}, {@link #typeLabel}, {@link #varInTypeBind}, or {@link #namespaceBind}. * - *

Does not hold for {@link #varAndTypeDecl} or {@link #typeOnlyImportExport} as these - * do not occur in type annotations. + *

Does not hold for {@link #varAndTypeDecl}, {@link #typeOnlyImport}, or @{link {@link #typeOnlyExport} + * as these do not occur in type annotations. */ public boolean isInsideType() { return this == typeBind From 78954489fbf532b3c71b5c1ab519c00448286b65 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 21 Feb 2020 15:03:06 +0000 Subject: [PATCH 109/134] TS: Fix expected output --- .../TypeScript/ExportNamespaceSpecifier/test.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected index 6403f1793a4..ca8914da44f 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExportNamespaceSpecifier/test.expected @@ -1 +1 @@ -| reexport.ts:1:13:1:14 | ns | +| reexport.ts:1:8:1:14 | * as ns | From 01309d7c2ee8ceb399744cb4ed08ab1c488af759 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 11:38:05 +0000 Subject: [PATCH 110/134] TS: Add test for named re-export and exportsAs --- .../TypeScript/TypeOnlyImportExport/exportClass.ts | 1 + .../TypeOnlyImportExport/importRexportedClass.ts | 3 +++ .../TypeScript/TypeOnlyImportExport/namedReexport.ts | 1 + .../TypeScript/TypeOnlyImportExport/test.expected | 12 ++++++++++++ .../TypeScript/TypeOnlyImportExport/test.ql | 5 +++++ 5 files changed, 22 insertions(+) create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts new file mode 100644 index 00000000000..1ec0ebf40c5 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/exportClass.ts @@ -0,0 +1 @@ +export class C {} diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts new file mode 100644 index 00000000000..92b60b44ccf --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/importRexportedClass.ts @@ -0,0 +1,3 @@ +import type { C } from "./namedReexport"; + +let c: C; diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts new file mode 100644 index 00000000000..6fd9a22c067 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/namedReexport.ts @@ -0,0 +1 @@ +export type { C } from "./exportClass"; diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected index f4861fcc5ce..083b5a90be6 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.expected @@ -1,5 +1,7 @@ getAVarReference +| C | exportClass.ts:1:14:1:14 | C | | Foo | tst.ts:5:5:5:7 | Foo | +| c | importRexportedClass.ts:3:5:3:5 | c | | f | exportFunction.ts:1:17:1:17 | f | | ns | importFunction.ts:1:10:1:11 | ns | | ns | importFunction.ts:3:1:3:2 | ns | @@ -7,8 +9,18 @@ getAVarReference getAnExportAccess | Foo | tst.ts:3:15:3:17 | Foo | getATypeDecl +| C | exportClass.ts:1:14:1:14 | C | +| C | importRexportedClass.ts:1:15:1:15 | C | | Foo | tst.ts:1:15:1:17 | Foo | | ns | importFunction.ts:1:10:1:11 | ns | | types | tst.ts:7:18:7:22 | types | calls | importFunction.ts:3:1:3:6 | ns.f() | importType.ts:3:19:3:24 | f() {} | +exportsAs +| exportClass.ts:1:1:1:17 | export class C {} | C | C | type | +| exportClass.ts:1:1:1:17 | export class C {} | C | C | variable | +| exportFunction.ts:1:1:1:22 | export ... f() {} | f | f | variable | +| importType.ts:3:1:3:27 | export ... ) {} }; | ns | ns | variable | +| namedReexport.ts:1:1:1:39 | export ... Class"; | C | C | type | +| tst.ts:3:1:3:20 | export type { Foo }; | Foo | Foo | namespace | +| tst.ts:3:1:3:20 | export type { Foo }; | Foo | Foo | type | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql index 3c3b9bf2320..17939b3b380 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql +++ b/javascript/ql/test/library-tests/TypeScript/TypeOnlyImportExport/test.ql @@ -15,3 +15,8 @@ query TypeDecl getATypeDecl(LocalTypeName t) { query Function calls(DataFlow::InvokeNode invoke) { result = invoke.getACallee() } + +query predicate exportsAs(ExportDeclaration exprt, LexicalName v, string name, string kind) { + exprt.exportsAs(v, name) and + kind = v.getDeclarationSpace() +} From ae6887847640e49e87327599576744fe69bc5b6d Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 18 Feb 2020 15:49:31 +0100 Subject: [PATCH 111/134] C++: Cache DefaultTaintTracking This should speed up the overall suite, where `DefaultTaintTracking` is used in several queries. --- cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 668512cecde..638e0e0269c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -343,6 +343,7 @@ private Element adjustedSink(DataFlow::Node sink) { result.(AssignOperation).getAnOperand() = sink.asExpr() } +cached predicate tainted(Expr source, Element tainted) { exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink | cfg.hasFlow(getNodeForSource(source), sink) and @@ -350,6 +351,7 @@ predicate tainted(Expr source, Element tainted) { ) } +cached predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) { tainted(source, tainted) and globalVar = "" From 6360073da4e6283f1af448d9f9f29d30f69ca47d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 14:35:17 +0000 Subject: [PATCH 112/134] JS: Rephrase change note --- change-notes/1.24/analysis-javascript.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 5465bcdb6ae..cdfcb5e3caa 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -13,9 +13,9 @@ * The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries. -* Calls can now be resolved to class members in more cases, leading to more results from the security queries. - -* Calls through partial invocations such as `.bind()` are now analyzed more precisely, leading to more results from the security queries. +* The call graph construction has been improved a few ways, leading to more results from the security queries: + - Calls can now be resolved to indirectly-defined class members in more cases. + - Calls through partial invocations such as `.bind` can now be resolved in more cases. * Support for the following frameworks and libraries has been improved: - [Electron](https://electronjs.org/) From 2b997ec94a2c79d41a8a68475ba68f3f574a5e19 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Feb 2020 15:36:45 +0100 Subject: [PATCH 113/134] Python: Add Python 3 Imports tests from internal repo --- .../encoding_error/EncodingError.expected | 0 .../Imports/encoding_error/EncodingError.py | 7 ++++ .../encoding_error/EncodingError.qlref | 1 + .../syntax_error/EncodingError.expected | 1 + .../Imports/syntax_error/EncodingError.qlref | 1 + .../Imports/syntax_error/SyntaxError.expected | 1 + .../Imports/syntax_error/SyntaxError.qlref | 1 + .../Imports/syntax_error/bad_encoding.py | 12 ++++++ .../Imports/syntax_error/nonsense.py | 37 +++++++++++++++++++ .../query-tests/Imports/syntax_error/test.py | 1 + 10 files changed, 62 insertions(+) create mode 100644 python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.expected create mode 100644 python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.py create mode 100644 python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref create mode 100644 python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.expected create mode 100644 python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref create mode 100644 python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected create mode 100644 python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref create mode 100644 python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py create mode 100644 python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py create mode 100644 python/ql/test/3/query-tests/Imports/syntax_error/test.py diff --git a/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.expected b/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.py b/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.py new file mode 100644 index 00000000000..b1623e43952 --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.py @@ -0,0 +1,7 @@ +123456789 +223456789 +323456789 +423456789 +5234567ø9 +623456789 +723456789 diff --git a/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref b/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref new file mode 100644 index 00000000000..a7e91769ded --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref @@ -0,0 +1 @@ +Imports/EncodingError.ql diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.expected b/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.expected new file mode 100644 index 00000000000..32fa7b97bf1 --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.expected @@ -0,0 +1 @@ +| bad_encoding.py:11:19:11:19 | Encoding Error | 'utf-8' codec can't decode byte 0x82 in position 82: invalid start byte | diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref b/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref new file mode 100644 index 00000000000..e742356f865 --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref @@ -0,0 +1 @@ +Imports/EncodingError.ql \ No newline at end of file diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected new file mode 100644 index 00000000000..1dfa8041767 --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected @@ -0,0 +1 @@ +| nonsense.py:1:2:1:2 | Syntax Error | Syntax Error (in Python 3.5). | diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref new file mode 100644 index 00000000000..c143a01fe8b --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref @@ -0,0 +1 @@ +Imports/SyntaxError.ql \ No newline at end of file diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py b/python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py new file mode 100644 index 00000000000..9c61b1e1b11 --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py @@ -0,0 +1,12 @@ +"""Multi-line docstring + + + + +""" + +# encoding:shift-jis + +def f(): + print "Python ‚ÌŠJ”­‚ÍA1990 ”N‚²‚ë‚©‚çŠJŽn‚³‚ê‚Ä‚¢‚Ü‚·" +""" diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py b/python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py new file mode 100644 index 00000000000..66cdd526fba --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py @@ -0,0 +1,37 @@ + `Twas brillig, and the slithy toves + Did gyre and gimble in the wabe: +All mimsy were the borogoves, + And the mome raths outgrabe. + + +"Beware the Jabberwock, my son! + The jaws that bite, the claws that catch! +Beware the Jubjub bird, and shun + The frumious Bandersnatch!" + +He took his vorpal sword in hand: + Long time the manxome foe he sought -- +So rested he by the Tumtum tree, + And stood awhile in thought. + +And, as in uffish thought he stood, + The Jabberwock, with eyes of flame, +Came whiffling through the tulgey wood, + And burbled as it came! + +One, two! One, two! And through and through + The vorpal blade went snicker-snack! +He left it dead, and with its head + He went galumphing back. + +"And, has thou slain the Jabberwock? + Come to my arms, my beamish boy! +O frabjous day! Callooh! Callay!' + He chortled in his joy. + + +`Twas brillig, and the slithy toves + Did gyre and gimble in the wabe; +All mimsy were the borogoves, + And the mome raths outgrabe. + diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/test.py b/python/ql/test/3/query-tests/Imports/syntax_error/test.py new file mode 100644 index 00000000000..ce438bd29eb --- /dev/null +++ b/python/ql/test/3/query-tests/Imports/syntax_error/test.py @@ -0,0 +1 @@ +print "Hello World" From e665e3c18748af6f135dd582e912fffa98fdc2b4 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 24 Feb 2020 15:07:28 +0000 Subject: [PATCH 114/134] Update change-notes/1.24/analysis-javascript.md Co-Authored-By: Esben Sparre Andreasen --- change-notes/1.24/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index cdfcb5e3caa..56a85ae3541 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -13,7 +13,7 @@ * The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries. -* The call graph construction has been improved a few ways, leading to more results from the security queries: +* The call graph construction has been improved, leading to more results from the security queries: - Calls can now be resolved to indirectly-defined class members in more cases. - Calls through partial invocations such as `.bind` can now be resolved in more cases. From 9f271949d5519b9c964fc7f6b040230470f9db9f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 24 Feb 2020 15:52:31 +0000 Subject: [PATCH 115/134] C++: Adjust layout of the argvlocal test. --- .../query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c | 2 ++ .../Security/CWE/CWE-134/semmle/argv/argvLocal.expected | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c index e83c6061f95..8669a4bf587 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c @@ -151,12 +151,14 @@ int main(int argc, char **argv) { printWrapper(i8); // BAD: i9 value comes from argv + char *i9; memcpy(1 ? i9++ : 0, argv[1], 1); printf(i9); printWrapper(i9); // BAD: i91 value comes from argv + char *i91; memcpy(0 ? 0 : (char *)((int) i91 * 2), argv[1], 1); printf(i91); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index ea24f969f34..c8fc21f0f0c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -18,5 +18,5 @@ | argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | | argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | -| argvLocal.c:167:18:167:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:166:18:166:21 | argv | argv | -| argvLocal.c:168:24:168:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:166:18:166:21 | argv | argv | +| argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:168:18:168:21 | argv | argv | +| argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:168:18:168:21 | argv | argv | From 4af0193c987b15e08e40a0407635926efdf7b66e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 24 Feb 2020 15:51:23 +0000 Subject: [PATCH 116/134] C++: Modify the argvlocal tests. --- .../Security/CWE/CWE-134/semmle/argv/argvLocal.c | 14 +++++++------- .../CWE/CWE-134/semmle/argv/argvLocal.expected | 6 ++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c index 8669a4bf587..beaad7d0fd3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.c @@ -146,21 +146,21 @@ int main(int argc, char **argv) { // BAD: i8 value comes from argv char *i8; - *(&i8 + 1) = argv[1]; + *(&i8) = argv[1]; printf(i8); printWrapper(i8); // BAD: i9 value comes from argv - - char *i9; - memcpy(1 ? i9++ : 0, argv[1], 1); + char i9buf[32]; + char *i9 = i9buf; + memcpy(1 ? ++i9 : 0, argv[1], 1); printf(i9); printWrapper(i9); // BAD: i91 value comes from argv - - char *i91; - memcpy(0 ? 0 : (char *)((int) i91 * 2), argv[1], 1); + char i91buf[64]; + char *i91 = &i91buf[0]; + memcpy(0 ? 0 : i91, argv[1] + 1, 1); printf(i91); printWrapper(i91); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index c8fc21f0f0c..7f342b0aabe 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -18,5 +18,11 @@ | argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | | argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | +| argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:11:149:14 | argv | argv | +| argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:11:149:14 | argv | argv | +| argvLocal.c:157:9:157:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:156:23:156:26 | argv | argv | +| argvLocal.c:158:15:158:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:156:23:156:26 | argv | argv | +| argvLocal.c:164:9:164:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:163:22:163:25 | argv | argv | +| argvLocal.c:165:15:165:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:163:22:163:25 | argv | argv | | argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:168:18:168:21 | argv | argv | | argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:168:18:168:21 | argv | argv | From 86b836cd2929d785b6411fea1278277edcede20b Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 29 Jan 2020 21:19:52 +0100 Subject: [PATCH 117/134] JS: add tests for js/path-injection --- .../CWE-022/TaintedPath/Consistency.expected | 3 + .../CWE-022/TaintedPath/TaintedPath.expected | 149 ++++++++++++++++++ .../CWE-022/TaintedPath/normalizedPaths.js | 38 +++++ 3 files changed, 190 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected index 68ed692f741..69bd82e188b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected @@ -1,4 +1,7 @@ | normalizedPaths.js:208:38:208:63 | // OK - ... anyway | Spurious alert | +| normalizedPaths.js:259:26:259:30 | // OK | Spurious alert | +| normalizedPaths.js:275:36:275:40 | // OK | Spurious alert | +| normalizedPaths.js:282:36:282:40 | // OK | Spurious alert | | tainted-string-steps.js:25:43:25:74 | // NOT ... flagged | Missing alert | | tainted-string-steps.js:26:49:26:74 | // OK - ... flagged | Spurious alert | | tainted-string-steps.js:28:39:28:70 | // NOT ... flagged | Missing alert | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index e3eeb351190..9b5075f47bb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1495,6 +1495,65 @@ nodes | normalizedPaths.js:250:21:250:24 | path | | normalizedPaths.js:250:21:250:24 | path | | normalizedPaths.js:250:21:250:24 | path | +| normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | +| normalizedPaths.js:256:13:256:26 | req.query.path | +| normalizedPaths.js:256:13:256:26 | req.query.path | +| normalizedPaths.js:256:13:256:26 | req.query.path | +| normalizedPaths.js:256:13:256:26 | req.query.path | +| normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:273:6:273:49 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | +| normalizedPaths.js:273:23:273:49 | pathMod ... , path) | +| normalizedPaths.js:273:23:273:49 | pathMod ... , path) | +| normalizedPaths.js:273:23:273:49 | pathMod ... , path) | +| normalizedPaths.js:273:45:273:48 | path | +| normalizedPaths.js:273:45:273:48 | path | +| normalizedPaths.js:273:45:273:48 | path | +| normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:285:19:285:32 | normalizedPath | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -4228,6 +4287,87 @@ edges | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:236:14:236:47 | pathMod ... y.path) | | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:236:14:236:47 | pathMod ... y.path) | | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:236:14:236:47 | pathMod ... y.path) | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:273:45:273:48 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:273:45:273:48 | path | +| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:273:45:273:48 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | +| normalizedPaths.js:273:23:273:49 | pathMod ... , path) | normalizedPaths.js:273:6:273:49 | normalizedPath | +| normalizedPaths.js:273:23:273:49 | pathMod ... , path) | normalizedPaths.js:273:6:273:49 | normalizedPath | +| normalizedPaths.js:273:23:273:49 | pathMod ... , path) | normalizedPaths.js:273:6:273:49 | normalizedPath | +| normalizedPaths.js:273:45:273:48 | path | normalizedPaths.js:273:23:273:49 | pathMod ... , path) | +| normalizedPaths.js:273:45:273:48 | path | normalizedPaths.js:273:23:273:49 | pathMod ... , path) | +| normalizedPaths.js:273:45:273:48 | path | normalizedPaths.js:273:23:273:49 | pathMod ... , path) | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -5096,6 +5236,15 @@ edges | normalizedPaths.js:238:19:238:22 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:238:19:238:22 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | | normalizedPaths.js:245:21:245:24 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:245:21:245:24 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | | normalizedPaths.js:250:21:250:24 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:250:21:250:24 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | +| normalizedPaths.js:257:18:257:21 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:257:18:257:21 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:259:19:259:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:259:19:259:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:262:19:262:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:262:19:262:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:266:19:266:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:266:19:266:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:269:19:269:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:269:19:269:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:275:19:275:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:275:19:275:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:278:19:278:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:278:19:278:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:282:19:282:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:282:19:282:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | +| normalizedPaths.js:285:19:285:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:285:19:285:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js index c0be777dd84..286d4bbedbe 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js @@ -249,3 +249,41 @@ app.get('/resolve-path', (req, res) => { else fs.readFileSync(path); // NOT OK - wrong polarity }); + +var isPathInside = require("is-path-inside"), + pathIsInside = require("path-is-inside"); +app.get('/pseudo-normalizations', (req, res) => { + let path = req.query.path; + fs.readFileSync(path); // NOT OK + if (isPathInside(path, SAFE)) { + fs.readFileSync(path); // OK + return; + } else { + fs.readFileSync(path); // NOT OK + + } + if (pathIsInside(path, SAFE)) { + fs.readFileSync(path); // NOT OK - can be of the form 'safe/directory/../../../etc/passwd' + return; + } else { + fs.readFileSync(path); // NOT OK + + } + + let normalizedPath = pathModule.join(SAFE, path); + if (pathIsInside(normalizedPath, SAFE)) { + fs.readFileSync(normalizedPath); // OK + return; + } else { + fs.readFileSync(normalizedPath); // NOT OK + } + + if (pathIsInside(normalizedPath, SAFE)) { + fs.readFileSync(normalizedPath); // OK + return; + } else { + fs.readFileSync(normalizedPath); // NOT OK + + } + +}); From 5baba62154e02807ef4a253463e7c86d655e0701 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 24 Feb 2020 22:48:09 +0100 Subject: [PATCH 118/134] JS: model `path-is-inside`+`is-path-inside` for `js/path-injection` --- .../security/dataflow/TaintedPath.qll | 3 +- .../dataflow/TaintedPathCustomizations.qll | 33 ++++++++++++++++ .../CWE-022/TaintedPath/Consistency.expected | 3 -- .../CWE-022/TaintedPath/TaintedPath.expected | 39 ------------------- 4 files changed, 35 insertions(+), 43 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index 8af939e56f3..bb9750677cc 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -35,7 +35,8 @@ module TaintedPath { guard instanceof StartsWithDotDotSanitizer or guard instanceof StartsWithDirSanitizer or guard instanceof IsAbsoluteSanitizer or - guard instanceof ContainsDotDotSanitizer + guard instanceof ContainsDotDotSanitizer or + guard instanceof IsInsideCheckSanitizer } override predicate isAdditionalFlowStep( diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 1117b70a9fd..1f9b8962301 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -369,6 +369,39 @@ module TaintedPath { */ private class VarAccessBarrier extends Sanitizer, DataFlow::VarAccessBarrier { } + /** + * An expression of form `isInside(x, y)` or similar, where `isInside` is + * a library check for the relation between `x` and `y`. + */ + class IsInsideCheckSanitizer extends DataFlow::LabeledBarrierGuardNode { + DataFlow::Node checked; + boolean onlyNormalizedAbsolutePaths; + + IsInsideCheckSanitizer() { + exists(string name, DataFlow::CallNode check | + name = "path-is-inside" and onlyNormalizedAbsolutePaths = true + or + name = "is-path-inside" and onlyNormalizedAbsolutePaths = false + | + check = DataFlow::moduleImport(name).getACall() and + checked = check.getArgument(0) and + check = this + ) + } + + override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) { + ( + onlyNormalizedAbsolutePaths = true and + label.(Label::PosixPath).isNormalized() and + label.(Label::PosixPath).isAbsolute() + or + onlyNormalizedAbsolutePaths = false + ) and + e = checked.asExpr() and + outcome = true + } + } + /** * A source of remote user input, considered as a flow source for * tainted-path vulnerabilities. diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected index 69bd82e188b..68ed692f741 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected @@ -1,7 +1,4 @@ | normalizedPaths.js:208:38:208:63 | // OK - ... anyway | Spurious alert | -| normalizedPaths.js:259:26:259:30 | // OK | Spurious alert | -| normalizedPaths.js:275:36:275:40 | // OK | Spurious alert | -| normalizedPaths.js:282:36:282:40 | // OK | Spurious alert | | tainted-string-steps.js:25:43:25:74 | // NOT ... flagged | Missing alert | | tainted-string-steps.js:26:49:26:74 | // OK - ... flagged | Spurious alert | | tainted-string-steps.js:28:39:28:70 | // NOT ... flagged | Missing alert | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 9b5075f47bb..54be1da5f1c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1509,11 +1509,6 @@ nodes | normalizedPaths.js:257:18:257:21 | path | | normalizedPaths.js:257:18:257:21 | path | | normalizedPaths.js:257:18:257:21 | path | -| normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:259:19:259:22 | path | | normalizedPaths.js:262:19:262:22 | path | | normalizedPaths.js:262:19:262:22 | path | | normalizedPaths.js:262:19:262:22 | path | @@ -1523,7 +1518,6 @@ nodes | normalizedPaths.js:266:19:266:22 | path | | normalizedPaths.js:266:19:266:22 | path | | normalizedPaths.js:266:19:266:22 | path | -| normalizedPaths.js:266:19:266:22 | path | | normalizedPaths.js:269:19:269:22 | path | | normalizedPaths.js:269:19:269:22 | path | | normalizedPaths.js:269:19:269:22 | path | @@ -1538,18 +1532,10 @@ nodes | normalizedPaths.js:273:45:273:48 | path | | normalizedPaths.js:273:45:273:48 | path | | normalizedPaths.js:273:45:273:48 | path | -| normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:275:19:275:32 | normalizedPath | | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:278:19:278:32 | normalizedPath | -| normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:282:19:282:32 | normalizedPath | | normalizedPaths.js:285:19:285:32 | normalizedPath | | normalizedPaths.js:285:19:285:32 | normalizedPath | | normalizedPaths.js:285:19:285:32 | normalizedPath | @@ -4295,14 +4281,6 @@ edges | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:257:18:257:21 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:259:19:259:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:262:19:262:22 | path | @@ -4317,8 +4295,6 @@ edges | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | -| normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:266:19:266:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | | normalizedPaths.js:256:6:256:26 | path | normalizedPaths.js:269:19:269:22 | path | @@ -4338,24 +4314,12 @@ edges | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:256:6:256:26 | path | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:275:19:275:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:278:19:278:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | -| normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:282:19:282:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | | normalizedPaths.js:273:6:273:49 | normalizedPath | normalizedPaths.js:285:19:285:32 | normalizedPath | @@ -5237,13 +5201,10 @@ edges | normalizedPaths.js:245:21:245:24 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:245:21:245:24 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | | normalizedPaths.js:250:21:250:24 | path | normalizedPaths.js:236:33:236:46 | req.query.path | normalizedPaths.js:250:21:250:24 | path | This path depends on $@. | normalizedPaths.js:236:33:236:46 | req.query.path | a user-provided value | | normalizedPaths.js:257:18:257:21 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:257:18:257:21 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | -| normalizedPaths.js:259:19:259:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:259:19:259:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | | normalizedPaths.js:262:19:262:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:262:19:262:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | | normalizedPaths.js:266:19:266:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:266:19:266:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | | normalizedPaths.js:269:19:269:22 | path | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:269:19:269:22 | path | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | -| normalizedPaths.js:275:19:275:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:275:19:275:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | | normalizedPaths.js:278:19:278:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:278:19:278:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | -| normalizedPaths.js:282:19:282:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:282:19:282:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | | normalizedPaths.js:285:19:285:32 | normalizedPath | normalizedPaths.js:256:13:256:26 | req.query.path | normalizedPaths.js:285:19:285:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:256:13:256:26 | req.query.path | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | From fba877241111d08bbe59090db81fbe2b5600a286 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 24 Feb 2020 09:13:56 +0100 Subject: [PATCH 119/134] Java/C++: Minor dataflow cleanup. --- .../code/cpp/dataflow/internal/DataFlowDispatch.qll | 2 -- .../code/cpp/dataflow/internal/DataFlowPrivate.qll | 10 ---------- .../code/cpp/ir/dataflow/internal/DataFlowDispatch.qll | 2 -- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 10 ---------- .../code/java/dataflow/internal/DataFlowPrivate.qll | 2 +- 5 files changed, 1 insertion(+), 25 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll index 75b77771e84..154430794d4 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll @@ -1,7 +1,5 @@ private import cpp -Function viableImpl(Call call) { result = viableCallable(call) } - /** * Gets a function that might be called by `call`. */ diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index dc035ec8681..a0fd5dc4c50 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -132,16 +132,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { */ predicate jumpStep(Node n1, Node n2) { none() } -/** - * Holds if `call` passes an implicit or explicit qualifier, i.e., a - * `this` parameter. - */ -predicate callHasQualifier(Call call) { - call.hasQualifier() - or - call.getTarget() instanceof Destructor -} - private newtype TContent = TFieldContent(Field f) or TCollectionContent() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index cebeda25a6e..f1d8c21595e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -3,8 +3,6 @@ private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.dataflow.DataFlow private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate -Function viableImpl(CallInstruction call) { result = viableCallable(call) } - /** * Gets a function that might be called by `call`. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index b6d3db23c96..83e5d5eb06b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -67,16 +67,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { */ predicate jumpStep(Node n1, Node n2) { none() } -/** - * Holds if `call` passes an implicit or explicit qualifier, i.e., a - * `this` parameter. - */ -predicate callHasQualifier(Call call) { - call.hasQualifier() - or - call.getTarget() instanceof Destructor -} - private newtype TContent = TFieldContent(Field f) or TCollectionContent() or diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index daf09497dc4..27d80d8df8d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -120,7 +120,7 @@ predicate jumpStep(Node node1, Node node2) { * Holds if `fa` is an access to an instance field that occurs as the * destination of an assignment of the value `src`. */ -predicate instanceFieldAssign(Expr src, FieldAccess fa) { +private predicate instanceFieldAssign(Expr src, FieldAccess fa) { exists(AssignExpr a | a.getSource() = src and a.getDest() = fa and From c2a3af7e67431a8c91bf6dc7af5040af6895d251 Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 10:48:29 -0800 Subject: [PATCH 120/134] Adds objectapi suffix to private predicates --- python/ql/src/Expressions/CallArgs.qll | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index fc61f38a826..2839d64d1e5 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -2,7 +2,7 @@ import python import Testing.Mox -private int varargs_length(Call call) { +private int varargs_length_objectapi(Call call) { not exists(call.getStarargs()) and result = 0 or exists(TupleObject t | @@ -14,7 +14,7 @@ private int varargs_length(Call call) { } /** Gets a keyword argument that is not a keyword-only parameter. */ -private Keyword not_keyword_only_arg(Call call, FunctionObject func) { +private Keyword not_keyword_only_arg_objectapi(Call call, FunctionObject func) { func.getACall().getNode() = call and result = call.getAKeyword() and not func.getFunction().getAKeywordOnlyArg().getId() = result.getArg() @@ -26,26 +26,26 @@ private Keyword not_keyword_only_arg(Call call, FunctionObject func) { * plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs). */ -private int positional_arg_count_for_call(Call call, Object callable) { - call = get_a_call(callable).getNode() and +private int positional_arg_count_for_call_objectapi(Call call, Object callable) { + call = get_a_call_objectapi(callable).getNode() and exists(int positional_keywords | exists(FunctionObject func | func = get_function_or_initializer(callable) | not func.getFunction().hasKwArg() and - positional_keywords = count(not_keyword_only_arg(call, func)) + positional_keywords = count(not_keyword_only_arg_objectapi(call, func)) or func.getFunction().hasKwArg() and positional_keywords = 0 ) | - result = count(call.getAnArg()) + varargs_length(call) + positional_keywords + result = count(call.getAnArg()) + varargs_length_objectapi(call) + positional_keywords ) } int arg_count(Call call) { - result = count(call.getAnArg()) + varargs_length(call) + count(call.getAKeyword()) + result = count(call.getAnArg()) + varargs_length_objectapi(call) + count(call.getAKeyword()) } /* Gets a call corresponding to the given class or function*/ -private ControlFlowNode get_a_call(Object callable) { +private ControlFlowNode get_a_call_objectapi(Object callable) { result = callable.(ClassObject).getACall() or result = callable.(FunctionObject).getACall() @@ -63,7 +63,7 @@ FunctionObject get_function_or_initializer(Object func_or_cls) { predicate illegally_named_parameter(Call call, Object func, string name) { not func.isC() and name = call.getANamedArgumentName() and - call.getAFlowNode() = get_a_call(func) and + call.getAFlowNode() = get_a_call_objectapi(func) and not get_function_or_initializer(func).isLegalArgumentName(name) } @@ -84,7 +84,7 @@ predicate too_few_args(Call call, Object callable, int limit) { call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1 or callable instanceof ClassObject and - call.getAFlowNode() = get_a_call(callable) and limit = func.minParameters() - 1 + call.getAFlowNode() = get_a_call_objectapi(callable) and limit = func.minParameters() - 1 ) } @@ -101,9 +101,9 @@ predicate too_many_args(Call call, Object callable, int limit) { call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 or callable instanceof ClassObject and - call.getAFlowNode() = get_a_call(callable) and limit = func.maxParameters() - 1 + call.getAFlowNode() = get_a_call_objectapi(callable) and limit = func.maxParameters() - 1 ) and - positional_arg_count_for_call(call, callable) > limit + positional_arg_count_for_call_objectapi(call, callable) > limit } /** Holds if `call` has too many or too few arguments for `func` */ From cf4b7e127037f3b37ad61351daa1a5036b1db82c Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 10:50:30 -0800 Subject: [PATCH 121/134] Swaps arg_count globally --- python/ql/src/Expressions/CallArgs.qll | 12 ++++++------ .../IncorrectlySpecifiedOverriddenMethod.ql | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 2839d64d1e5..772af8922d5 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -26,7 +26,7 @@ private Keyword not_keyword_only_arg_objectapi(Call call, FunctionObject func) { * plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs). */ -private int positional_arg_count_for_call_objectapi(Call call, Object callable) { +private int positional_arg_count_objectapi_for_call_objectapi(Call call, Object callable) { call = get_a_call_objectapi(callable).getNode() and exists(int positional_keywords | exists(FunctionObject func | func = get_function_or_initializer(callable) | @@ -40,7 +40,7 @@ private int positional_arg_count_for_call_objectapi(Call call, Object callable) ) } -int arg_count(Call call) { +int arg_count_objectapi(Call call) { result = count(call.getAnArg()) + varargs_length_objectapi(call) + count(call.getAKeyword()) } @@ -72,7 +72,7 @@ predicate too_few_args(Call call, Object callable, int limit) { // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' not illegally_named_parameter(call, callable, _) and not exists(call.getStarargs()) and not exists(call.getKwargs()) and - arg_count(call) < limit and + arg_count_objectapi(call) < limit and exists(FunctionObject func | func = get_function_or_initializer(callable) | call = func.getAFunctionCall().getNode() and limit = func.minParameters() and /* The combination of misuse of `mox.Mox().StubOutWithMock()` @@ -103,7 +103,7 @@ predicate too_many_args(Call call, Object callable, int limit) { callable instanceof ClassObject and call.getAFlowNode() = get_a_call_objectapi(callable) and limit = func.maxParameters() - 1 ) and - positional_arg_count_for_call_objectapi(call, callable) > limit + positional_arg_count_objectapi_for_call_objectapi(call, callable) > limit } /** Holds if `call` has too many or too few arguments for `func` */ @@ -118,9 +118,9 @@ predicate wrong_args(Call call, FunctionObject func, int limit, string too) { */ bindingset[call, func] predicate correct_args_if_called_as_method(Call call, FunctionObject func) { - arg_count(call)+1 >= func.minParameters() + arg_count_objectapi(call)+1 >= func.minParameters() and - arg_count(call) < func.maxParameters() + arg_count_objectapi(call) < func.maxParameters() } /** Holds if `call` is a call to `overriding`, which overrides `func`. */ diff --git a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql index 3af03a23602..5f83f9ae6f6 100644 --- a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql @@ -20,9 +20,9 @@ overriding.overrides(func) and call = overriding.getAMethodCall().getNode() and correct_args_if_called_as_method(call, overriding) and ( - arg_count(call)+1 < func.minParameters() and problem = "too few arguments" + arg_count_objectapi(call)+1 < func.minParameters() and problem = "too few arguments" or - arg_count(call) >= func.maxParameters() and problem = "too many arguments" + arg_count_objectapi(call) >= func.maxParameters() and problem = "too many arguments" or exists(string name | call.getAKeyword().getArg() = name and overriding.getFunction().getAnArg().(Name).getId() = name and From 4857a947accd4a5e2d71c61eefcaafbb6d988729 Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 10:51:40 -0800 Subject: [PATCH 122/134] Swaps get_function_or_initializer globally --- .../WrongNameForArgumentInClassInstantiation.ql | 2 +- .../WrongNumberArgumentsInClassInstantiation.ql | 2 +- python/ql/src/Expressions/CallArgs.qll | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql index 33bf524ae94..9296009c06f 100644 --- a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql @@ -21,7 +21,7 @@ import Expressions.CallArgs from Call call, ClassObject cls, string name, FunctionObject init where illegally_named_parameter(call, cls, name) - and init = get_function_or_initializer(cls) + and init = get_function_or_initializer_objectapi(cls) select call, "Keyword argument '" + name + "' is not a supported parameter name of $@.", init, init.getQualifiedName() diff --git a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql index 915856319e0..bd9f053272f 100644 --- a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql @@ -21,5 +21,5 @@ where too_many_args(call, cls, limit) and too = "too many arguments" and should = "no more than " or too_few_args(call, cls, limit) and too = "too few arguments" and should = "no fewer than " -) and init = get_function_or_initializer(cls) +) and init = get_function_or_initializer_objectapi(cls) select call, "Call to $@ with " + too + "; should be " + should + limit.toString() + ".", init, init.getQualifiedName() diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 772af8922d5..13a4798af9b 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -29,7 +29,7 @@ private Keyword not_keyword_only_arg_objectapi(Call call, FunctionObject func) { private int positional_arg_count_objectapi_for_call_objectapi(Call call, Object callable) { call = get_a_call_objectapi(callable).getNode() and exists(int positional_keywords | - exists(FunctionObject func | func = get_function_or_initializer(callable) | + exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) | not func.getFunction().hasKwArg() and positional_keywords = count(not_keyword_only_arg_objectapi(call, func)) or @@ -52,7 +52,7 @@ private ControlFlowNode get_a_call_objectapi(Object callable) { } /* Gets the function object corresponding to the given class or function*/ -FunctionObject get_function_or_initializer(Object func_or_cls) { +FunctionObject get_function_or_initializer_objectapi(Object func_or_cls) { result = func_or_cls.(FunctionObject) or result = func_or_cls.(ClassObject).declaredAttribute("__init__") @@ -64,7 +64,7 @@ predicate illegally_named_parameter(Call call, Object func, string name) { not func.isC() and name = call.getANamedArgumentName() and call.getAFlowNode() = get_a_call_objectapi(func) and - not get_function_or_initializer(func).isLegalArgumentName(name) + not get_function_or_initializer_objectapi(func).isLegalArgumentName(name) } /**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */ @@ -73,7 +73,7 @@ predicate too_few_args(Call call, Object callable, int limit) { not illegally_named_parameter(call, callable, _) and not exists(call.getStarargs()) and not exists(call.getKwargs()) and arg_count_objectapi(call) < limit and - exists(FunctionObject func | func = get_function_or_initializer(callable) | + exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) | call = func.getAFunctionCall().getNode() and limit = func.minParameters() and /* The combination of misuse of `mox.Mox().StubOutWithMock()` * and a bug in mox's implementation of methods results in having to @@ -93,7 +93,7 @@ predicate too_many_args(Call call, Object callable, int limit) { // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' not illegally_named_parameter(call, callable, _) and exists(FunctionObject func | - func = get_function_or_initializer(callable) and + func = get_function_or_initializer_objectapi(callable) and not func.getFunction().hasVarArg() and limit >= 0 | call = func.getAFunctionCall().getNode() and limit = func.maxParameters() From 2c32a859cc1ed5e29a0f6505497c7f3d0d22b75a Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 10:58:08 -0800 Subject: [PATCH 123/134] Swaps illegally_named_parameter globally --- .../src/Classes/WrongNameForArgumentInClassInstantiation.ql | 2 +- python/ql/src/Expressions/CallArgs.qll | 6 +++--- python/ql/src/Expressions/WrongNameForArgumentInCall.ql | 2 +- python/ql/src/Functions/IncorrectlyOverriddenMethod.ql | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql index 9296009c06f..022d6a515e6 100644 --- a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql @@ -20,7 +20,7 @@ import Expressions.CallArgs from Call call, ClassObject cls, string name, FunctionObject init where - illegally_named_parameter(call, cls, name) + illegally_named_parameter_objectapi(call, cls, name) and init = get_function_or_initializer_objectapi(cls) select call, "Keyword argument '" + name + "' is not a supported parameter name of $@.", init, init.getQualifiedName() diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 13a4798af9b..5e12f1e4557 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -60,7 +60,7 @@ FunctionObject get_function_or_initializer_objectapi(Object func_or_cls) { /**Whether there is an illegally named parameter called `name` in the `call` to `func` */ -predicate illegally_named_parameter(Call call, Object func, string name) { +predicate illegally_named_parameter_objectapi(Call call, Object func, string name) { not func.isC() and name = call.getANamedArgumentName() and call.getAFlowNode() = get_a_call_objectapi(func) and @@ -70,7 +70,7 @@ predicate illegally_named_parameter(Call call, Object func, string name) { /**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */ predicate too_few_args(Call call, Object callable, int limit) { // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' - not illegally_named_parameter(call, callable, _) and + not illegally_named_parameter_objectapi(call, callable, _) and not exists(call.getStarargs()) and not exists(call.getKwargs()) and arg_count_objectapi(call) < limit and exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) | @@ -91,7 +91,7 @@ predicate too_few_args(Call call, Object callable, int limit) { /**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */ predicate too_many_args(Call call, Object callable, int limit) { // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' - not illegally_named_parameter(call, callable, _) and + not illegally_named_parameter_objectapi(call, callable, _) and exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) and not func.getFunction().hasVarArg() and limit >= 0 diff --git a/python/ql/src/Expressions/WrongNameForArgumentInCall.ql b/python/ql/src/Expressions/WrongNameForArgumentInCall.ql index 92c17f8e2ee..6abab859f5f 100644 --- a/python/ql/src/Expressions/WrongNameForArgumentInCall.ql +++ b/python/ql/src/Expressions/WrongNameForArgumentInCall.ql @@ -19,7 +19,7 @@ import Expressions.CallArgs from Call call, FunctionObject func, string name where -illegally_named_parameter(call, func, name) and +illegally_named_parameter_objectapi(call, func, name) and not func.isAbstract() and not exists(FunctionObject overridden | func.overrides(overridden) and overridden.getFunction().getAnArg().(Name).getId() = name) select diff --git a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql index e5d3947a1a7..c918f06da85 100644 --- a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql @@ -18,7 +18,7 @@ func.overrides(overridden) and ( wrong_args(call, func, _, problem) and correct_args_if_called_as_method(call, overridden) or exists(string name | - illegally_named_parameter(call, func, name) and problem = "an argument named '" + name + "'" and + illegally_named_parameter_objectapi(call, func, name) and problem = "an argument named '" + name + "'" and overridden.getFunction().getAnArg().(Name).getId() = name ) ) From 3b0be4637756f17b0949c7df32cc190bdb726d1f Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 10:59:16 -0800 Subject: [PATCH 124/134] Swaps too_few_args globally --- .../src/Classes/WrongNumberArgumentsInClassInstantiation.ql | 2 +- python/ql/src/Expressions/CallArgs.qll | 4 ++-- python/ql/src/Expressions/WrongNumberArgumentsInCall.ql | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql index bd9f053272f..7880d911c92 100644 --- a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql @@ -20,6 +20,6 @@ where ( too_many_args(call, cls, limit) and too = "too many arguments" and should = "no more than " or - too_few_args(call, cls, limit) and too = "too few arguments" and should = "no fewer than " + too_few_args_objectapi(call, cls, limit) and too = "too few arguments" and should = "no fewer than " ) and init = get_function_or_initializer_objectapi(cls) select call, "Call to $@ with " + too + "; should be " + should + limit.toString() + ".", init, init.getQualifiedName() diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 5e12f1e4557..87076c94507 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -68,7 +68,7 @@ predicate illegally_named_parameter_objectapi(Call call, Object func, string nam } /**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */ -predicate too_few_args(Call call, Object callable, int limit) { +predicate too_few_args_objectapi(Call call, Object callable, int limit) { // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' not illegally_named_parameter_objectapi(call, callable, _) and not exists(call.getStarargs()) and not exists(call.getKwargs()) and @@ -108,7 +108,7 @@ predicate too_many_args(Call call, Object callable, int limit) { /** Holds if `call` has too many or too few arguments for `func` */ predicate wrong_args(Call call, FunctionObject func, int limit, string too) { - too_few_args(call, func, limit) and too = "too few" + too_few_args_objectapi(call, func, limit) and too = "too few" or too_many_args(call, func, limit) and too = "too many" } diff --git a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql index b31e9e70445..c8017010021 100644 --- a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql +++ b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql @@ -19,7 +19,7 @@ where ( too_many_args(call, func, limit) and too = "too many arguments" and should = "no more than " or - too_few_args(call, func, limit) and too = "too few arguments" and should = "no fewer than " + too_few_args_objectapi(call, func, limit) and too = "too few arguments" and should = "no fewer than " ) and not func.isAbstract() and not exists(FunctionObject overridden | func.overrides(overridden) and correct_args_if_called_as_method(call, overridden)) From 3a764ade8db86b7bc1454d2da44b83d3be2c3e18 Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 10:59:55 -0800 Subject: [PATCH 125/134] Swaps too_many_args globally --- .../src/Classes/WrongNumberArgumentsInClassInstantiation.ql | 2 +- python/ql/src/Expressions/CallArgs.qll | 4 ++-- python/ql/src/Expressions/WrongNumberArgumentsInCall.ql | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql index 7880d911c92..f94b5ac5b3e 100644 --- a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql @@ -18,7 +18,7 @@ import Expressions.CallArgs from Call call, ClassObject cls, string too, string should, int limit, FunctionObject init where ( - too_many_args(call, cls, limit) and too = "too many arguments" and should = "no more than " + too_many_args_objectapi(call, cls, limit) and too = "too many arguments" and should = "no more than " or too_few_args_objectapi(call, cls, limit) and too = "too few arguments" and should = "no fewer than " ) and init = get_function_or_initializer_objectapi(cls) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 87076c94507..a551536e55a 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -89,7 +89,7 @@ predicate too_few_args_objectapi(Call call, Object callable, int limit) { } /**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */ -predicate too_many_args(Call call, Object callable, int limit) { +predicate too_many_args_objectapi(Call call, Object callable, int limit) { // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' not illegally_named_parameter_objectapi(call, callable, _) and exists(FunctionObject func | @@ -110,7 +110,7 @@ predicate too_many_args(Call call, Object callable, int limit) { predicate wrong_args(Call call, FunctionObject func, int limit, string too) { too_few_args_objectapi(call, func, limit) and too = "too few" or - too_many_args(call, func, limit) and too = "too many" + too_many_args_objectapi(call, func, limit) and too = "too many" } /** Holds if `call` has correct number of arguments for `func`. diff --git a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql index c8017010021..d1bee018463 100644 --- a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql +++ b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql @@ -17,7 +17,7 @@ import CallArgs from Call call, FunctionObject func, string too, string should, int limit where ( - too_many_args(call, func, limit) and too = "too many arguments" and should = "no more than " + too_many_args_objectapi(call, func, limit) and too = "too many arguments" and should = "no more than " or too_few_args_objectapi(call, func, limit) and too = "too few arguments" and should = "no fewer than " ) and From fb0cae76cfb101753cb9a66f7ef813560073472b Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 11:00:39 -0800 Subject: [PATCH 126/134] Swaps wrong_args globally --- python/ql/src/Expressions/CallArgs.qll | 2 +- python/ql/src/Functions/IncorrectlyOverriddenMethod.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index a551536e55a..8bc95d7beb4 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -107,7 +107,7 @@ predicate too_many_args_objectapi(Call call, Object callable, int limit) { } /** Holds if `call` has too many or too few arguments for `func` */ -predicate wrong_args(Call call, FunctionObject func, int limit, string too) { +predicate wrong_args_objectapi(Call call, FunctionObject func, int limit, string too) { too_few_args_objectapi(call, func, limit) and too = "too few" or too_many_args_objectapi(call, func, limit) and too = "too many" diff --git a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql index c918f06da85..f0e88502b8b 100644 --- a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql @@ -15,7 +15,7 @@ import Expressions.CallArgs from Call call, FunctionObject func, FunctionObject overridden, string problem where func.overrides(overridden) and ( - wrong_args(call, func, _, problem) and correct_args_if_called_as_method(call, overridden) + wrong_args_objectapi(call, func, _, problem) and correct_args_if_called_as_method(call, overridden) or exists(string name | illegally_named_parameter_objectapi(call, func, name) and problem = "an argument named '" + name + "'" and From 50c91b99da76a634b0e6540dc247f509366cff89 Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 11:01:51 -0800 Subject: [PATCH 127/134] Swaps correct_args_if_called_as_method globally --- python/ql/src/Expressions/CallArgs.qll | 2 +- python/ql/src/Expressions/WrongNumberArgumentsInCall.ql | 2 +- python/ql/src/Functions/IncorrectlyOverriddenMethod.ql | 2 +- python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 8bc95d7beb4..065dabd77e7 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -117,7 +117,7 @@ predicate wrong_args_objectapi(Call call, FunctionObject func, int limit, string * Implies nothing about whether `call` could call `func`. */ bindingset[call, func] -predicate correct_args_if_called_as_method(Call call, FunctionObject func) { +predicate correct_args_if_called_as_method_objectapi(Call call, FunctionObject func) { arg_count_objectapi(call)+1 >= func.minParameters() and arg_count_objectapi(call) < func.maxParameters() diff --git a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql index d1bee018463..9f636213a34 100644 --- a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql +++ b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql @@ -22,7 +22,7 @@ where too_few_args_objectapi(call, func, limit) and too = "too few arguments" and should = "no fewer than " ) and not func.isAbstract() and -not exists(FunctionObject overridden | func.overrides(overridden) and correct_args_if_called_as_method(call, overridden)) +not exists(FunctionObject overridden | func.overrides(overridden) and correct_args_if_called_as_method_objectapi(call, overridden)) /* The semantics of `__new__` can be a bit subtle, so we simply exclude `__new__` methods */ and not func.getName() = "__new__" diff --git a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql index f0e88502b8b..a425079cce0 100644 --- a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql @@ -15,7 +15,7 @@ import Expressions.CallArgs from Call call, FunctionObject func, FunctionObject overridden, string problem where func.overrides(overridden) and ( - wrong_args_objectapi(call, func, _, problem) and correct_args_if_called_as_method(call, overridden) + wrong_args_objectapi(call, func, _, problem) and correct_args_if_called_as_method_objectapi(call, overridden) or exists(string name | illegally_named_parameter_objectapi(call, func, name) and problem = "an argument named '" + name + "'" and diff --git a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql index 5f83f9ae6f6..9636c7c22db 100644 --- a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql @@ -18,7 +18,7 @@ where not func.getName() = "__init__" and overriding.overrides(func) and call = overriding.getAMethodCall().getNode() and -correct_args_if_called_as_method(call, overriding) and +correct_args_if_called_as_method_objectapi(call, overriding) and ( arg_count_objectapi(call)+1 < func.minParameters() and problem = "too few arguments" or From e07a003f75a31aaea38a030d12fbd11b4dba69de Mon Sep 17 00:00:00 2001 From: Rebecca Valentine Date: Tue, 25 Feb 2020 11:02:18 -0800 Subject: [PATCH 128/134] Swaps overridden_call globally --- python/ql/src/Expressions/CallArgs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 065dabd77e7..72326a1c30c 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -124,7 +124,7 @@ predicate correct_args_if_called_as_method_objectapi(Call call, FunctionObject f } /** Holds if `call` is a call to `overriding`, which overrides `func`. */ -predicate overridden_call(FunctionObject func, FunctionObject overriding, Call call) { +predicate overridden_call_objectapi(FunctionObject func, FunctionObject overriding, Call call) { overriding.overrides(func) and overriding.getACall().getNode() = call } From cd5399d43eac9ee95c36c795247b3573a9d8bb7f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Feb 2020 14:55:52 +0100 Subject: [PATCH 129/134] Python: Model outgoing http client requests --- .../semmle/python/web/ClientHttpRequest.qll | 2 + python/ql/src/semmle/python/web/Http.qll | 46 +++++++++++++++- .../src/semmle/python/web/client/Requests.qll | 22 ++++++++ .../src/semmle/python/web/client/StdLib.qll | 52 +++++++++++++++++++ .../client/stdlib/ClientHttpRequests.expected | 10 ++++ .../web/client/stdlib/ClientHttpRequests.ql | 11 ++++ .../2/library-tests/web/client/stdlib/test.py | 37 +++++++++++++ .../client/stdlib/ClientHttpRequests.expected | 10 ++++ .../web/client/stdlib/ClientHttpRequests.ql | 11 ++++ .../3/library-tests/web/client/stdlib/test.py | 37 +++++++++++++ .../requests/ClientHttpRequests.expected | 2 + .../web/client/requests/ClientHttpRequests.ql | 11 ++++ .../library-tests/web/client/requests/options | 1 + .../library-tests/web/client/requests/test.py | 4 ++ .../client/stdlib/ClientHttpRequests.expected | 10 ++++ .../web/client/stdlib/ClientHttpRequests.ql | 11 ++++ .../library-tests/web/client/stdlib/options | 1 + .../library-tests/web/client/stdlib/test.py | 38 ++++++++++++++ 18 files changed, 314 insertions(+), 2 deletions(-) create mode 100644 python/ql/src/semmle/python/web/ClientHttpRequest.qll create mode 100644 python/ql/src/semmle/python/web/client/Requests.qll create mode 100644 python/ql/src/semmle/python/web/client/StdLib.qll create mode 100644 python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected create mode 100644 python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.ql create mode 100644 python/ql/test/2/library-tests/web/client/stdlib/test.py create mode 100644 python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected create mode 100644 python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql create mode 100644 python/ql/test/3/library-tests/web/client/stdlib/test.py create mode 100644 python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected create mode 100644 python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql create mode 100644 python/ql/test/library-tests/web/client/requests/options create mode 100644 python/ql/test/library-tests/web/client/requests/test.py create mode 100644 python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected create mode 100644 python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql create mode 100644 python/ql/test/library-tests/web/client/stdlib/options create mode 100644 python/ql/test/library-tests/web/client/stdlib/test.py diff --git a/python/ql/src/semmle/python/web/ClientHttpRequest.qll b/python/ql/src/semmle/python/web/ClientHttpRequest.qll new file mode 100644 index 00000000000..edcd236e031 --- /dev/null +++ b/python/ql/src/semmle/python/web/ClientHttpRequest.qll @@ -0,0 +1,2 @@ +import semmle.python.web.client.StdLib +import semmle.python.web.client.Requests diff --git a/python/ql/src/semmle/python/web/Http.qll b/python/ql/src/semmle/python/web/Http.qll index ce9435a63ec..7500ddc7c3e 100644 --- a/python/ql/src/semmle/python/web/Http.qll +++ b/python/ql/src/semmle/python/web/Http.qll @@ -89,7 +89,7 @@ abstract class CookieSet extends CookieOperation {} /** Generic taint sink in a http response */ abstract class HttpResponseTaintSink extends TaintSink { - override predicate sinks(TaintKind kind) { + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } @@ -97,9 +97,51 @@ abstract class HttpResponseTaintSink extends TaintSink { abstract class HttpRedirectTaintSink extends TaintSink { - override predicate sinks(TaintKind kind) { + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } +module Client { + + // TODO: user-input in other than URL: + // - `data`, `json` for `requests.post` + // - `body` for `HTTPConnection.request` + // - headers? + + // TODO: Add more library support + // - urllib3 https://github.com/urllib3/urllib3 + // - httpx https://github.com/encode/httpx + + /** + * An outgoing http request + * + * For example: + * conn = HTTPConnection('example.com') + conn.request('GET', '/path') + */ + abstract class HttpRequest extends CallNode { + + /** Get any ControlFlowNode that is used to construct the final URL. + * + * In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`. + */ + abstract ControlFlowNode getAUrlPart(); + + abstract string getMethodUpper(); + } + + /** Taint sink for the URL-part of an outgoing http request */ + class HttpRequestUrlTaintSink extends TaintSink { + + HttpRequestUrlTaintSink() { + this = any(HttpRequest r).getAUrlPart() + } + + override predicate sinks(TaintKind kind) { + kind instanceof ExternalStringKind + } + + } +} diff --git a/python/ql/src/semmle/python/web/client/Requests.qll b/python/ql/src/semmle/python/web/client/Requests.qll new file mode 100644 index 00000000000..243f0dab7a2 --- /dev/null +++ b/python/ql/src/semmle/python/web/client/Requests.qll @@ -0,0 +1,22 @@ +/** + * Modeling outgoing HTTP requests using the `requests` package + * https://pypi.org/project/requests/ + */ + +import python +private import semmle.python.web.Http + +class RequestsHttpRequest extends Client::HttpRequest { + CallableValue func; + string method; + + RequestsHttpRequest() { + method = httpVerbLower() and + func = Module::named("requests").attr(method).(CallableValue) and + this = func.getACall() + } + + override ControlFlowNode getAUrlPart() { result = func.getNamedArgumentForCall(this, "url") } + + override string getMethodUpper() { result = method.toUpperCase() } +} diff --git a/python/ql/src/semmle/python/web/client/StdLib.qll b/python/ql/src/semmle/python/web/client/StdLib.qll new file mode 100644 index 00000000000..24d6f549dc3 --- /dev/null +++ b/python/ql/src/semmle/python/web/client/StdLib.qll @@ -0,0 +1,52 @@ +import python +private import semmle.python.web.Http + +ClassValue httpConnectionClass() { + // Python 2 + result = Value::named("httplib.HTTPConnection") + or + result = Value::named("httplib.HTTPSConnection") + or + // Python 3 + result = Value::named("http.client.HTTPConnection") + or + result = Value::named("http.client.HTTPSConnection") + or + // six + result = Value::named("six.moves.http_client.HTTPConnection") + or + result = Value::named("six.moves.http_client.HTTPSConnection") +} + +class HttpConnectionHttpRequest extends Client::HttpRequest { + CallNode constructor_call; + CallableValue func; + + HttpConnectionHttpRequest() { + exists(ClassValue cls, AttrNode call_origin, Value constructor_call_value | + cls = httpConnectionClass() and + func = cls.lookup("request") and + this = func.getACall() and + this.getFunction().pointsTo(_, _, call_origin) and + call_origin.getObject().pointsTo(_, constructor_call_value, constructor_call) and + cls = constructor_call_value.getClass() and + constructor_call = cls.getACall() + ) + + } + + override ControlFlowNode getAUrlPart() { + result = func.getNamedArgumentForCall(this, "url") + or + result = constructor_call.getArg(0) + or + result = constructor_call.getArgByName("host") + } + + override string getMethodUpper() { + exists(string method | + result = method.toUpperCase() and + func.getNamedArgumentForCall(this, "method").pointsTo(Value::forString(method)) + ) + } +} diff --git a/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected b/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected new file mode 100644 index 00000000000..d2766eeeb59 --- /dev/null +++ b/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected @@ -0,0 +1,10 @@ +| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:5:27:5:39 | ControlFlowNode for Str | GET | +| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:6:25:6:31 | ControlFlowNode for Str | GET | +| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:10:28:10:40 | ControlFlowNode for Str | POST | +| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:15:26:15:32 | ControlFlowNode for Str | POST | +| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:19:27:19:39 | ControlFlowNode for Str | | +| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:20:26:20:32 | ControlFlowNode for Str | | +| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:28:27:28:30 | ControlFlowNode for fake | GET | +| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:30:25:30:31 | ControlFlowNode for Str | GET | +| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:35:27:35:39 | ControlFlowNode for Str | HEAD | +| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:37:22:37:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.ql b/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.ql new file mode 100644 index 00000000000..cbeed6c2e4b --- /dev/null +++ b/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.ql @@ -0,0 +1,11 @@ +import python + +import semmle.python.web.Http +import semmle.python.web.ClientHttpRequest + +from Client::HttpRequest req, string method +where + if exists(req.getMethodUpper()) + then method = req.getMethodUpper() + else method = "" +select req, req.getAUrlPart(), method diff --git a/python/ql/test/2/library-tests/web/client/stdlib/test.py b/python/ql/test/2/library-tests/web/client/stdlib/test.py new file mode 100644 index 00000000000..a95c3d81783 --- /dev/null +++ b/python/ql/test/2/library-tests/web/client/stdlib/test.py @@ -0,0 +1,37 @@ +from httplib import HTTPConnection, HTTPSConnection + + +def basic(): + conn = HTTPConnection('example.com') + conn.request('GET', '/path') + + +def indirect_caller(): + conn = HTTPSConnection('example.com') + indirect_callee(conn) + + +def indirect_callee(conn): + conn.request('POST', '/path') + + +def method_not_known(method): + conn = HTTPConnection('example.com') + conn.request(method, '/path') + + +def sneaky_setting_host(): + # We don't handle that the host is overwritten directly. + # A contrived example; you're not supposed to do this, but you certainly can. + fake = 'fakehost.com' + real = 'realhost.com' + conn = HTTPConnection(fake) + conn.host = real + conn.request('GET', '/path') + + +def tricky_not_attribute_node(): + # A contrived example; you're not supposed to do this, but you certainly can. + conn = HTTPConnection('example.com') + req_meth = conn.request + req_meth('HEAD', '/path') diff --git a/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected b/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected new file mode 100644 index 00000000000..d2766eeeb59 --- /dev/null +++ b/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected @@ -0,0 +1,10 @@ +| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:5:27:5:39 | ControlFlowNode for Str | GET | +| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:6:25:6:31 | ControlFlowNode for Str | GET | +| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:10:28:10:40 | ControlFlowNode for Str | POST | +| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:15:26:15:32 | ControlFlowNode for Str | POST | +| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:19:27:19:39 | ControlFlowNode for Str | | +| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:20:26:20:32 | ControlFlowNode for Str | | +| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:28:27:28:30 | ControlFlowNode for fake | GET | +| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:30:25:30:31 | ControlFlowNode for Str | GET | +| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:35:27:35:39 | ControlFlowNode for Str | HEAD | +| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:37:22:37:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql b/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql new file mode 100644 index 00000000000..cbeed6c2e4b --- /dev/null +++ b/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql @@ -0,0 +1,11 @@ +import python + +import semmle.python.web.Http +import semmle.python.web.ClientHttpRequest + +from Client::HttpRequest req, string method +where + if exists(req.getMethodUpper()) + then method = req.getMethodUpper() + else method = "" +select req, req.getAUrlPart(), method diff --git a/python/ql/test/3/library-tests/web/client/stdlib/test.py b/python/ql/test/3/library-tests/web/client/stdlib/test.py new file mode 100644 index 00000000000..551660d5548 --- /dev/null +++ b/python/ql/test/3/library-tests/web/client/stdlib/test.py @@ -0,0 +1,37 @@ +from http.client import HTTPConnection, HTTPSConnection + + +def basic(): + conn = HTTPConnection('example.com') + conn.request('GET', '/path') + + +def indirect_caller(): + conn = HTTPSConnection('example.com') + indirect_callee(conn) + + +def indirect_callee(conn): + conn.request('POST', '/path') + + +def method_not_known(method): + conn = HTTPConnection('example.com') + conn.request(method, '/path') + + +def sneaky_setting_host(): + # We don't handle that the host is overwritten directly. + # A contrived example; you're not supposed to do this, but you certainly can. + fake = 'fakehost.com' + real = 'realhost.com' + conn = HTTPConnection(fake) + conn.host = real + conn.request('GET', '/path') + + +def tricky_not_attribute_node(): + # A contrived example; you're not supposed to do this, but you certainly can. + conn = HTTPConnection('example.com') + req_meth = conn.request + req_meth('HEAD', '/path') diff --git a/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected new file mode 100644 index 00000000000..73ce6ba748c --- /dev/null +++ b/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected @@ -0,0 +1,2 @@ +| test.py:3:1:3:27 | ControlFlowNode for Attribute() | test.py:3:14:3:26 | ControlFlowNode for Str | GET | +| test.py:4:1:4:28 | ControlFlowNode for Attribute() | test.py:4:15:4:27 | ControlFlowNode for Str | POST | diff --git a/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql b/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql new file mode 100644 index 00000000000..cbeed6c2e4b --- /dev/null +++ b/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql @@ -0,0 +1,11 @@ +import python + +import semmle.python.web.Http +import semmle.python.web.ClientHttpRequest + +from Client::HttpRequest req, string method +where + if exists(req.getMethodUpper()) + then method = req.getMethodUpper() + else method = "" +select req, req.getAUrlPart(), method diff --git a/python/ql/test/library-tests/web/client/requests/options b/python/ql/test/library-tests/web/client/requests/options new file mode 100644 index 00000000000..f1858a6caf9 --- /dev/null +++ b/python/ql/test/library-tests/web/client/requests/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../../../query-tests/Security/lib/ --max-import-depth=1 diff --git a/python/ql/test/library-tests/web/client/requests/test.py b/python/ql/test/library-tests/web/client/requests/test.py new file mode 100644 index 00000000000..1cb5e47e166 --- /dev/null +++ b/python/ql/test/library-tests/web/client/requests/test.py @@ -0,0 +1,4 @@ +import requests + +requests.get('example.com') +requests.post('example.com') diff --git a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected new file mode 100644 index 00000000000..fe8cd1ea0c7 --- /dev/null +++ b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected @@ -0,0 +1,10 @@ +| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:6:27:6:39 | ControlFlowNode for Str | GET | +| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:7:25:7:31 | ControlFlowNode for Str | GET | +| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:11:28:11:40 | ControlFlowNode for Str | POST | +| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:16:26:16:32 | ControlFlowNode for Str | POST | +| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:20:27:20:39 | ControlFlowNode for Str | | +| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:21:26:21:32 | ControlFlowNode for Str | | +| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:29:27:29:30 | ControlFlowNode for fake | GET | +| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:31:25:31:31 | ControlFlowNode for Str | GET | +| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:36:27:36:39 | ControlFlowNode for Str | HEAD | +| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:38:22:38:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql new file mode 100644 index 00000000000..cbeed6c2e4b --- /dev/null +++ b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql @@ -0,0 +1,11 @@ +import python + +import semmle.python.web.Http +import semmle.python.web.ClientHttpRequest + +from Client::HttpRequest req, string method +where + if exists(req.getMethodUpper()) + then method = req.getMethodUpper() + else method = "" +select req, req.getAUrlPart(), method diff --git a/python/ql/test/library-tests/web/client/stdlib/options b/python/ql/test/library-tests/web/client/stdlib/options new file mode 100644 index 00000000000..b91afde0767 --- /dev/null +++ b/python/ql/test/library-tests/web/client/stdlib/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 diff --git a/python/ql/test/library-tests/web/client/stdlib/test.py b/python/ql/test/library-tests/web/client/stdlib/test.py new file mode 100644 index 00000000000..313add907cf --- /dev/null +++ b/python/ql/test/library-tests/web/client/stdlib/test.py @@ -0,0 +1,38 @@ +from six.moves.http_client import HTTPConnection, HTTPSConnection +from six.moves.urllib.parse import urlsplit + + +def basic(): + conn = HTTPConnection('example.com') + conn.request('GET', '/path') + + +def indirect_caller(): + conn = HTTPSConnection('example.com') + indirect_callee(conn) + + +def indirect_callee(conn): + conn.request('POST', '/path') + + +def method_not_known(method): + conn = HTTPConnection('example.com') + conn.request(method, '/path') + + +def sneaky_setting_host(): + # We don't handle that the host is overwritten directly. + # A contrived example; you're not supposed to do this, but you certainly can. + fake = 'fakehost.com' + real = 'realhost.com' + conn = HTTPConnection(fake) + conn.host = real + conn.request('GET', '/path') + + +def tricky_not_attribute_node(): + # A contrived example; you're not supposed to do this, but you certainly can. + conn = HTTPConnection('example.com') + req_meth = conn.request + req_meth('HEAD', '/path') From e25079acc256457df1484731fad3c603a0db6a66 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 25 Feb 2020 16:08:00 +0100 Subject: [PATCH 130/134] Python: Remove unnecessary cast --- python/ql/src/semmle/python/web/client/Requests.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/web/client/Requests.qll b/python/ql/src/semmle/python/web/client/Requests.qll index 243f0dab7a2..5f837e50245 100644 --- a/python/ql/src/semmle/python/web/client/Requests.qll +++ b/python/ql/src/semmle/python/web/client/Requests.qll @@ -12,7 +12,7 @@ class RequestsHttpRequest extends Client::HttpRequest { RequestsHttpRequest() { method = httpVerbLower() and - func = Module::named("requests").attr(method).(CallableValue) and + func = Module::named("requests").attr(method) and this = func.getACall() } From be187bcc0a08e6e7bd178c0939604cd0df6e21a4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 25 Feb 2020 16:09:32 +0100 Subject: [PATCH 131/134] Python: Make Client::HttpRequest extend ControlFlowNode Taus poitned out that the reuqest being send off, doesn't *need* to happen on a CallNode. Someone *could* use a __setattr__ or property :\ --- python/ql/src/semmle/python/web/Http.qll | 2 +- python/ql/src/semmle/python/web/client/Requests.qll | 2 +- python/ql/src/semmle/python/web/client/StdLib.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/web/Http.qll b/python/ql/src/semmle/python/web/Http.qll index 7500ddc7c3e..80b8885d62e 100644 --- a/python/ql/src/semmle/python/web/Http.qll +++ b/python/ql/src/semmle/python/web/Http.qll @@ -121,7 +121,7 @@ module Client { * conn = HTTPConnection('example.com') conn.request('GET', '/path') */ - abstract class HttpRequest extends CallNode { + abstract class HttpRequest extends ControlFlowNode { /** Get any ControlFlowNode that is used to construct the final URL. * diff --git a/python/ql/src/semmle/python/web/client/Requests.qll b/python/ql/src/semmle/python/web/client/Requests.qll index 5f837e50245..6899c651fa6 100644 --- a/python/ql/src/semmle/python/web/client/Requests.qll +++ b/python/ql/src/semmle/python/web/client/Requests.qll @@ -6,7 +6,7 @@ import python private import semmle.python.web.Http -class RequestsHttpRequest extends Client::HttpRequest { +class RequestsHttpRequest extends Client::HttpRequest, CallNode { CallableValue func; string method; diff --git a/python/ql/src/semmle/python/web/client/StdLib.qll b/python/ql/src/semmle/python/web/client/StdLib.qll index 24d6f549dc3..60a2000c750 100644 --- a/python/ql/src/semmle/python/web/client/StdLib.qll +++ b/python/ql/src/semmle/python/web/client/StdLib.qll @@ -18,7 +18,7 @@ ClassValue httpConnectionClass() { result = Value::named("six.moves.http_client.HTTPSConnection") } -class HttpConnectionHttpRequest extends Client::HttpRequest { +class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode { CallNode constructor_call; CallableValue func; From b213db03fdd42deef43dc96262bdacd3646fc69c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 25 Feb 2020 16:30:44 +0100 Subject: [PATCH 132/134] Python: Consolidate stdlib http client tests Move the stdlib tests from test/{2,3}/library-tests/ into /test/library-tests/, and deal with version by using sys.version_info (results should be the same for both versions). six tests were moved from /library-tests/web/client/stdlib => /library-tests/web/client/six --- .../client/stdlib/ClientHttpRequests.expected | 10 ----- .../2/library-tests/web/client/stdlib/test.py | 37 ------------------- .../client/stdlib/ClientHttpRequests.expected | 10 ----- .../web/client/stdlib/ClientHttpRequests.ql | 11 ------ .../client/six/ClientHttpRequests.expected | 10 +++++ .../web/client/six}/ClientHttpRequests.ql | 0 .../test/library-tests/web/client/six/options | 2 + .../web/client/six}/test.py | 3 +- .../client/stdlib/ClientHttpRequests.expected | 20 +++++----- .../library-tests/web/client/stdlib/options | 2 +- .../library-tests/web/client/stdlib/test.py | 10 ++++- 11 files changed, 33 insertions(+), 82 deletions(-) delete mode 100644 python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected delete mode 100644 python/ql/test/2/library-tests/web/client/stdlib/test.py delete mode 100644 python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected delete mode 100644 python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql create mode 100644 python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected rename python/ql/test/{2/library-tests/web/client/stdlib => library-tests/web/client/six}/ClientHttpRequests.ql (100%) create mode 100644 python/ql/test/library-tests/web/client/six/options rename python/ql/test/{3/library-tests/web/client/stdlib => library-tests/web/client/six}/test.py (88%) diff --git a/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected b/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected deleted file mode 100644 index d2766eeeb59..00000000000 --- a/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.expected +++ /dev/null @@ -1,10 +0,0 @@ -| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:5:27:5:39 | ControlFlowNode for Str | GET | -| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:6:25:6:31 | ControlFlowNode for Str | GET | -| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:10:28:10:40 | ControlFlowNode for Str | POST | -| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:15:26:15:32 | ControlFlowNode for Str | POST | -| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:19:27:19:39 | ControlFlowNode for Str | | -| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:20:26:20:32 | ControlFlowNode for Str | | -| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:28:27:28:30 | ControlFlowNode for fake | GET | -| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:30:25:30:31 | ControlFlowNode for Str | GET | -| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:35:27:35:39 | ControlFlowNode for Str | HEAD | -| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:37:22:37:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/2/library-tests/web/client/stdlib/test.py b/python/ql/test/2/library-tests/web/client/stdlib/test.py deleted file mode 100644 index a95c3d81783..00000000000 --- a/python/ql/test/2/library-tests/web/client/stdlib/test.py +++ /dev/null @@ -1,37 +0,0 @@ -from httplib import HTTPConnection, HTTPSConnection - - -def basic(): - conn = HTTPConnection('example.com') - conn.request('GET', '/path') - - -def indirect_caller(): - conn = HTTPSConnection('example.com') - indirect_callee(conn) - - -def indirect_callee(conn): - conn.request('POST', '/path') - - -def method_not_known(method): - conn = HTTPConnection('example.com') - conn.request(method, '/path') - - -def sneaky_setting_host(): - # We don't handle that the host is overwritten directly. - # A contrived example; you're not supposed to do this, but you certainly can. - fake = 'fakehost.com' - real = 'realhost.com' - conn = HTTPConnection(fake) - conn.host = real - conn.request('GET', '/path') - - -def tricky_not_attribute_node(): - # A contrived example; you're not supposed to do this, but you certainly can. - conn = HTTPConnection('example.com') - req_meth = conn.request - req_meth('HEAD', '/path') diff --git a/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected b/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected deleted file mode 100644 index d2766eeeb59..00000000000 --- a/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.expected +++ /dev/null @@ -1,10 +0,0 @@ -| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:5:27:5:39 | ControlFlowNode for Str | GET | -| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:6:25:6:31 | ControlFlowNode for Str | GET | -| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:10:28:10:40 | ControlFlowNode for Str | POST | -| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:15:26:15:32 | ControlFlowNode for Str | POST | -| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:19:27:19:39 | ControlFlowNode for Str | | -| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:20:26:20:32 | ControlFlowNode for Str | | -| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:28:27:28:30 | ControlFlowNode for fake | GET | -| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:30:25:30:31 | ControlFlowNode for Str | GET | -| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:35:27:35:39 | ControlFlowNode for Str | HEAD | -| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:37:22:37:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql b/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql deleted file mode 100644 index cbeed6c2e4b..00000000000 --- a/python/ql/test/3/library-tests/web/client/stdlib/ClientHttpRequests.ql +++ /dev/null @@ -1,11 +0,0 @@ -import python - -import semmle.python.web.Http -import semmle.python.web.ClientHttpRequest - -from Client::HttpRequest req, string method -where - if exists(req.getMethodUpper()) - then method = req.getMethodUpper() - else method = "" -select req, req.getAUrlPart(), method diff --git a/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected new file mode 100644 index 00000000000..fe8cd1ea0c7 --- /dev/null +++ b/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected @@ -0,0 +1,10 @@ +| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:6:27:6:39 | ControlFlowNode for Str | GET | +| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:7:25:7:31 | ControlFlowNode for Str | GET | +| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:11:28:11:40 | ControlFlowNode for Str | POST | +| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:16:26:16:32 | ControlFlowNode for Str | POST | +| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:20:27:20:39 | ControlFlowNode for Str | | +| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:21:26:21:32 | ControlFlowNode for Str | | +| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:29:27:29:30 | ControlFlowNode for fake | GET | +| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:31:25:31:31 | ControlFlowNode for Str | GET | +| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:36:27:36:39 | ControlFlowNode for Str | HEAD | +| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:38:22:38:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.ql b/python/ql/test/library-tests/web/client/six/ClientHttpRequests.ql similarity index 100% rename from python/ql/test/2/library-tests/web/client/stdlib/ClientHttpRequests.ql rename to python/ql/test/library-tests/web/client/six/ClientHttpRequests.ql diff --git a/python/ql/test/library-tests/web/client/six/options b/python/ql/test/library-tests/web/client/six/options new file mode 100644 index 00000000000..1f95e64d742 --- /dev/null +++ b/python/ql/test/library-tests/web/client/six/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=2 +optimize: true diff --git a/python/ql/test/3/library-tests/web/client/stdlib/test.py b/python/ql/test/library-tests/web/client/six/test.py similarity index 88% rename from python/ql/test/3/library-tests/web/client/stdlib/test.py rename to python/ql/test/library-tests/web/client/six/test.py index 551660d5548..313add907cf 100644 --- a/python/ql/test/3/library-tests/web/client/stdlib/test.py +++ b/python/ql/test/library-tests/web/client/six/test.py @@ -1,4 +1,5 @@ -from http.client import HTTPConnection, HTTPSConnection +from six.moves.http_client import HTTPConnection, HTTPSConnection +from six.moves.urllib.parse import urlsplit def basic(): diff --git a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected index fe8cd1ea0c7..a514bbea41b 100644 --- a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected +++ b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected @@ -1,10 +1,10 @@ -| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:6:27:6:39 | ControlFlowNode for Str | GET | -| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:7:25:7:31 | ControlFlowNode for Str | GET | -| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:11:28:11:40 | ControlFlowNode for Str | POST | -| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:16:26:16:32 | ControlFlowNode for Str | POST | -| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:20:27:20:39 | ControlFlowNode for Str | | -| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:21:26:21:32 | ControlFlowNode for Str | | -| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:29:27:29:30 | ControlFlowNode for fake | GET | -| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:31:25:31:31 | ControlFlowNode for Str | GET | -| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:36:27:36:39 | ControlFlowNode for Str | HEAD | -| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:38:22:38:28 | ControlFlowNode for Str | HEAD | +| test.py:13:5:13:32 | ControlFlowNode for Attribute() | test.py:12:27:12:39 | ControlFlowNode for Str | GET | +| test.py:13:5:13:32 | ControlFlowNode for Attribute() | test.py:13:25:13:31 | ControlFlowNode for Str | GET | +| test.py:22:5:22:33 | ControlFlowNode for Attribute() | test.py:17:28:17:40 | ControlFlowNode for Str | POST | +| test.py:22:5:22:33 | ControlFlowNode for Attribute() | test.py:22:26:22:32 | ControlFlowNode for Str | POST | +| test.py:27:5:27:33 | ControlFlowNode for Attribute() | test.py:26:27:26:39 | ControlFlowNode for Str | | +| test.py:27:5:27:33 | ControlFlowNode for Attribute() | test.py:27:26:27:32 | ControlFlowNode for Str | | +| test.py:37:5:37:32 | ControlFlowNode for Attribute() | test.py:35:27:35:30 | ControlFlowNode for fake | GET | +| test.py:37:5:37:32 | ControlFlowNode for Attribute() | test.py:37:25:37:31 | ControlFlowNode for Str | GET | +| test.py:44:5:44:29 | ControlFlowNode for req_meth() | test.py:42:27:42:39 | ControlFlowNode for Str | HEAD | +| test.py:44:5:44:29 | ControlFlowNode for req_meth() | test.py:44:22:44:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/library-tests/web/client/stdlib/options b/python/ql/test/library-tests/web/client/stdlib/options index b91afde0767..eb214fc2931 100644 --- a/python/ql/test/library-tests/web/client/stdlib/options +++ b/python/ql/test/library-tests/web/client/stdlib/options @@ -1 +1 @@ -semmle-extractor-options: --max-import-depth=2 +semmle-extractor-options: --max-import-depth=1 diff --git a/python/ql/test/library-tests/web/client/stdlib/test.py b/python/ql/test/library-tests/web/client/stdlib/test.py index 313add907cf..179f9b30858 100644 --- a/python/ql/test/library-tests/web/client/stdlib/test.py +++ b/python/ql/test/library-tests/web/client/stdlib/test.py @@ -1,5 +1,11 @@ -from six.moves.http_client import HTTPConnection, HTTPSConnection -from six.moves.urllib.parse import urlsplit +import sys +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +if PY2: + from httplib import HTTPConnection, HTTPSConnection +if PY3: + from http.client import HTTPConnection, HTTPSConnection def basic(): From 5fae3a8d0a2e460001e30348f9b982f0e4d7b21d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 25 Feb 2020 16:41:01 +0100 Subject: [PATCH 133/134] Python: Explain complexity of HTTPConnection.request --- python/ql/src/semmle/python/web/client/StdLib.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/web/client/StdLib.qll b/python/ql/src/semmle/python/web/client/StdLib.qll index 60a2000c750..9ee089a47f5 100644 --- a/python/ql/src/semmle/python/web/client/StdLib.qll +++ b/python/ql/src/semmle/python/web/client/StdLib.qll @@ -27,12 +27,15 @@ class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode { cls = httpConnectionClass() and func = cls.lookup("request") and this = func.getACall() and + // since you can do `r = conn.request; r('GET', path)`, we need to find the origin this.getFunction().pointsTo(_, _, call_origin) and + // Since HTTPSConnection is a subtype of HTTPConnection, up until this point, `cls` could be either class, + // because `HTTPSConnection.request == HTTPConnection.request`. To avoid generating 2 results, we filter + // on the actual class used as the constructor call_origin.getObject().pointsTo(_, constructor_call_value, constructor_call) and cls = constructor_call_value.getClass() and constructor_call = cls.getACall() ) - } override ControlFlowNode getAUrlPart() { From 4330d4e28902566a128d0f6219f1939aba457a3a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 26 Feb 2020 10:25:15 +0100 Subject: [PATCH 134/134] Python: Remove unused import in test --- .../client/six/ClientHttpRequests.expected | 20 +++++++++---------- .../test/library-tests/web/client/six/test.py | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected index fe8cd1ea0c7..d2766eeeb59 100644 --- a/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected +++ b/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected @@ -1,10 +1,10 @@ -| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:6:27:6:39 | ControlFlowNode for Str | GET | -| test.py:7:5:7:32 | ControlFlowNode for Attribute() | test.py:7:25:7:31 | ControlFlowNode for Str | GET | -| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:11:28:11:40 | ControlFlowNode for Str | POST | -| test.py:16:5:16:33 | ControlFlowNode for Attribute() | test.py:16:26:16:32 | ControlFlowNode for Str | POST | -| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:20:27:20:39 | ControlFlowNode for Str | | -| test.py:21:5:21:33 | ControlFlowNode for Attribute() | test.py:21:26:21:32 | ControlFlowNode for Str | | -| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:29:27:29:30 | ControlFlowNode for fake | GET | -| test.py:31:5:31:32 | ControlFlowNode for Attribute() | test.py:31:25:31:31 | ControlFlowNode for Str | GET | -| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:36:27:36:39 | ControlFlowNode for Str | HEAD | -| test.py:38:5:38:29 | ControlFlowNode for req_meth() | test.py:38:22:38:28 | ControlFlowNode for Str | HEAD | +| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:5:27:5:39 | ControlFlowNode for Str | GET | +| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:6:25:6:31 | ControlFlowNode for Str | GET | +| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:10:28:10:40 | ControlFlowNode for Str | POST | +| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:15:26:15:32 | ControlFlowNode for Str | POST | +| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:19:27:19:39 | ControlFlowNode for Str | | +| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:20:26:20:32 | ControlFlowNode for Str | | +| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:28:27:28:30 | ControlFlowNode for fake | GET | +| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:30:25:30:31 | ControlFlowNode for Str | GET | +| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:35:27:35:39 | ControlFlowNode for Str | HEAD | +| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:37:22:37:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/library-tests/web/client/six/test.py b/python/ql/test/library-tests/web/client/six/test.py index 313add907cf..cdd79021d87 100644 --- a/python/ql/test/library-tests/web/client/six/test.py +++ b/python/ql/test/library-tests/web/client/six/test.py @@ -1,5 +1,4 @@ from six.moves.http_client import HTTPConnection, HTTPSConnection -from six.moves.urllib.parse import urlsplit def basic():