From 45805f3ed1c40e5f757dcedb80c649827c1b6eb9 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 29 Oct 2026 13:34:05 +0000 Subject: [PATCH 1/3] JS: Add shared SSA migration regression tests Add all migration regressions before changing the implementation. Mark main's known missing and spurious results inline, and record its current consistency-query output. Use the existing internal node names and compare public/native definition coordinates so these tests compile before the migration. The integration commit switches the representation-specific checks to native shared definitions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../BarrierGuardPhiInputs/test.expected | 0 .../BarrierGuardPhiInputs/test.ql | 47 ++ .../BarrierGuardPhiInputs/tst.js | 35 ++ .../SharedSsaCompatibility/captured.expected | 3 + .../SharedSsaCompatibility/captured.js | 114 ++++ .../SharedSsaCompatibility/captured.ql | 128 +++++ .../invariants.expected | 502 ++++++++++++++++++ .../SharedSsaCompatibility/invariants.ql | 62 +++ .../SharedSsaCompatibility/local.expected | 0 .../SharedSsaCompatibility/local.js | 192 +++++++ .../SharedSsaCompatibility/local.ql | 160 ++++++ .../SharedSsaCompatibility/namespace.ts | 9 + .../SharedSsaCompatibility/nodes.expected | 0 .../SharedSsaCompatibility/nodes.js | 88 +++ .../SharedSsaCompatibility/nodes.ql | 91 ++++ .../refinement.expected | 0 .../SharedSsaCompatibility/refinement.js | 493 +++++++++++++++++ .../SharedSsaCompatibility/refinement.ql | 119 +++++ .../SharedSsaCompatibility/test.expected | 0 .../SharedSsaCompatibility/test.ql | 44 ++ .../SharedSsaCompatibility/tst.js | 10 + .../SecondOrderCommandInjection.expected | 28 +- .../second-order.js | 9 +- 23 files changed, 2120 insertions(+), 14 deletions(-) create mode 100644 javascript/ql/test/library-tests/BarrierGuardPhiInputs/test.expected create mode 100644 javascript/ql/test/library-tests/BarrierGuardPhiInputs/test.ql create mode 100644 javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/captured.expected create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/captured.ql create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/local.expected create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/local.js create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/namespace.ts create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.expected create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.expected create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.ql create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/test.expected create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/test.ql create mode 100644 javascript/ql/test/library-tests/SharedSsaCompatibility/tst.js diff --git a/javascript/ql/test/library-tests/BarrierGuardPhiInputs/test.expected b/javascript/ql/test/library-tests/BarrierGuardPhiInputs/test.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/javascript/ql/test/library-tests/BarrierGuardPhiInputs/test.ql b/javascript/ql/test/library-tests/BarrierGuardPhiInputs/test.ql new file mode 100644 index 000000000000..a3f51c50e36a --- /dev/null +++ b/javascript/ql/test/library-tests/BarrierGuardPhiInputs/test.ql @@ -0,0 +1,47 @@ +import javascript +import utils.test.InlineExpectationsTest + +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.(DataFlow::InvokeNode).getCalleeName() = "SOURCE" + } + + predicate isSink(DataFlow::Node sink) { + exists(DataFlow::InvokeNode call | + call.getCalleeName() = "SINK" and + sink = call.getArgument(0) + ) + } + + predicate isBarrier(DataFlow::Node node) { + node = DataFlow::MakeBarrierGuard::getABarrierNode() + } +} + +module TestFlow = DataFlow::Global; + +class SimpleBarrierGuard extends DataFlow::InvokeNode { + SimpleBarrierGuard() { this.getCalleeName() = "BARRIER" } + + predicate blocksExpr(boolean outcome, Expr expr) { + outcome = true and + expr = this.getArgument(0).asExpr() + } +} + +module InlineTest implements TestSig { + string getARelevantTag() { result = "flow" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "flow" and + element = "" and + exists(DataFlow::InvokeNode source, DataFlow::Node sink | + TestFlow::flow(source, sink) and + source.getCalleeName() = "SOURCE" and + value = source.getArgument(0).getStringValue() and + location = sink.getLocation() + ) + } +} + +import MakeTest diff --git a/javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js b/javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js new file mode 100644 index 000000000000..07e217ad4849 --- /dev/null +++ b/javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js @@ -0,0 +1,35 @@ +function overwriteOnFailure() { + let x = SOURCE("overwrite"); + if (!BARRIER(x)) { + x = "safe"; + } + SINK(x); // $ SPURIOUS: flow=overwrite +} + +function explicitElse() { + let x = SOURCE("else"); + if (BARRIER(x)) { + use(x); + } else { + x = "safe"; + } + SINK(x); // $ SPURIOUS: flow=else +} + +function preserveUnguardedInput() { + let x = SOURCE("guarded"); + if (!BARRIER(x)) { + x = SOURCE("fallback"); + } + SINK(x); // $ flow=fallback SPURIOUS: flow=guarded +} + +function returnOnFailure() { + let x = SOURCE("return"); + if (!BARRIER(x)) { + return; + } + SINK(x); +} + +SINK(SOURCE("control")); // $ flow=control diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.expected b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.expected new file mode 100644 index 000000000000..6aa55dc337c7 --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.expected @@ -0,0 +1,3 @@ +WARNING: type 'BarrierGuardNode' has been deprecated and may be removed in future (captured.ql:32,40-66) +WARNING: type 'BarrierGuardNode' has been deprecated and may be removed in future (captured.ql:43,37-63) +WARNING: type 'Configuration' has been deprecated and may be removed in future (captured.ql:36,36-59) diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js new file mode 100644 index 000000000000..0018fbf34c12 --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js @@ -0,0 +1,114 @@ +import "dummy"; + +let capturedWrite = 0; // $ capturedWrite=capturedWrite ssaDefinition=capturedWrite noSsaAstNode=capturedWrite + +function readCaptured() { + return capturedWrite; // $ noCapturedWrite=capturedWrite +} + +function unreachableCapturedWrites() { + return; + capturedWrite = 2; // $ noCapturedWrite=capturedWrite +} + +function writeCaptured() { + capturedWrite = 1; // $ capturedWrite=capturedWrite ssaDefinition=capturedWrite + ++capturedWrite; // $ capturedWrite=capturedWrite ssaDefinition=capturedWrite + capturedWrite += 1; // $ capturedWrite=capturedWrite ssaDefinition=capturedWrite +} + +function uncapturedWrites() { + let uncapturedWrite = 0; // $ noCapturedWrite=uncapturedWrite + return uncapturedWrite++; // $ noCapturedWrite=uncapturedWrite +} + +globalWrite = 1; // $ noCapturedWrite=globalWrite +use(globalWrite); // $ noCapturedWrite=globalWrite + +const { capturedPattern } = input; // $ capturedWrite=capturedPattern ssaDefinition=capturedPattern +function readCapturedPattern() { + return capturedPattern; // $ noCapturedWrite=capturedPattern +} + +function destructuredDeclaration() { + const { declaredObject, safeObject } = { // $ ssaDefinition=declaredObject ssaDefinition=safeObject + declaredObject: SOURCE("object-declaration"), + safeObject: "safe" + }; + SINK(declaredObject); // $ localCapturedFlow=declaredObject capturedFlow=object-declaration legacyCapturedFlow=object-declaration + SINK(safeObject); // $ localCapturedFlow=safeObject + return () => { + SINK(declaredObject); // $ capturedFlow=object-declaration legacyCapturedFlow=object-declaration + SINK(safeObject); + }; +} +destructuredDeclaration()(); + +function destructuredAssignment() { + let assignedObject; + ({ assignedObject } = { assignedObject: SOURCE("object-assignment") }); // $ ssaDefinition=assignedObject + SINK(assignedObject); // $ localCapturedFlow=assignedObject capturedFlow=object-assignment legacyCapturedFlow=object-assignment + return () => SINK(assignedObject); // $ capturedFlow=object-assignment legacyCapturedFlow=object-assignment +} +destructuredAssignment()(); + +function destructuredParameter({ parameterObject }) { // $ ssaDefinition=parameterObject + SINK(parameterObject); // $ localCapturedFlow=parameterObject capturedFlow=object-parameter legacyCapturedFlow=object-parameter + return () => SINK(parameterObject); // $ capturedFlow=object-parameter legacyCapturedFlow=object-parameter +} +destructuredParameter({ parameterObject: SOURCE("object-parameter") })(); + +function destructuredLoop() { + for (const { loopObject } of [{ loopObject: SOURCE("object-loop") }]) { // $ ssaDefinition=loopObject + SINK(loopObject); // $ localCapturedFlow=loopObject capturedFlow=object-loop legacyCapturedFlow=object-loop + (() => SINK(loopObject))(); // $ capturedFlow=object-loop legacyCapturedFlow=object-loop + } +} +destructuredLoop(); + +function destructuredArray([arrayElement]) { // $ ssaDefinition=arrayElement + SINK(arrayElement); // $ localCapturedFlow=arrayElement capturedFlow=array-element legacyCapturedFlow=array-element + return () => SINK(arrayElement); // $ capturedFlow=array-element legacyCapturedFlow=array-element +} +destructuredArray([SOURCE("array-element")])(); + +const { topLevelObject } = { topLevelObject: SOURCE("top-level-object") }; // $ ssaDefinition=topLevelObject +function readTopLevelObject() { + SINK(topLevelObject); // $ capturedFlow=top-level-object legacyCapturedFlow=top-level-object +} +readTopLevelObject(); + +let topLevelPhi; +if (unknownCondition()) { + topLevelPhi = SOURCE("top-level-phi"); // $ ssaDefinition=topLevelPhi +} else { + topLevelPhi = "safe"; // $ ssaDefinition=topLevelPhi +} +SINK(topLevelPhi); // $ capturedFlow=top-level-phi legacyCapturedFlow=top-level-phi +function readTopLevelPhi() { + SINK(topLevelPhi); // $ capturedFlow=top-level-phi legacyCapturedFlow=top-level-phi +} +readTopLevelPhi(); + +function legacyGuardedPhi(condition) { + let value = SOURCE("legacy-guarded-phi"); + if (condition && BARRIER(value)) { + } else { + value = "safe"; + } + SINK(value); // $ SPURIOUS: capturedFlow=legacy-guarded-phi +} + +function legacyGuardedWithReads(condition) { + let value = SOURCE("legacy-with-guard"); + use(value); + with ({}) { + if (condition) { + if (!BARRIER(value)) return; + use(value); + } else { + value = "safe"; + } + } + SINK(value); // $ SPURIOUS: capturedFlow=legacy-with-guard +} diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.ql new file mode 100644 index 000000000000..7cebe78259ac --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.ql @@ -0,0 +1,128 @@ +import javascript +import utils.test.InlineExpectationsTest + +module CapturedConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.(DataFlow::InvokeNode).getCalleeName() = "SOURCE" + } + + predicate isSink(DataFlow::Node sink) { + exists(DataFlow::InvokeNode call | + call.getCalleeName() = "SINK" and + sink = call.getArgument(0) + ) + } + + predicate isBarrier(DataFlow::Node node) { + node = DataFlow::MakeBarrierGuard::getABarrierNode() + } +} + +module CapturedFlow = DataFlow::Global; + +class SimpleBarrierGuard extends DataFlow::InvokeNode { + SimpleBarrierGuard() { this.getCalleeName() = "BARRIER" } + + predicate blocksExpr(boolean outcome, Expr expr) { + outcome = true and + expr = this.getArgument(0).asExpr() + } +} + +class LegacySimpleBarrierGuard extends DataFlow::BarrierGuardNode, SimpleBarrierGuard { + override predicate blocks(boolean outcome, Expr expr) { this.blocksExpr(outcome, expr) } +} + +class LegacyCapturedConfig extends DataFlow::Configuration { + LegacyCapturedConfig() { this = "LegacyCapturedConfig" } + + override predicate isSource(DataFlow::Node source) { CapturedConfig::isSource(source) } + + override predicate isSink(DataFlow::Node sink) { CapturedConfig::isSink(sink) } + + override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) { + guard instanceof LegacySimpleBarrierGuard + } +} + +module InlineTest implements TestSig { + string getARelevantTag() { + result = + [ + "capturedWrite", "noCapturedWrite", "ssaDefinition", "noSsaAstNode", "localCapturedFlow", + "capturedFlow", "legacyCapturedFlow" + ] + } + + predicate hasActualResult(Location location, string element, string tag, string value) { + element = "" and + location.getFile().getBaseName() = "captured.js" and + ( + exists(VarRef reference | + value = reference.getVariable().getName() and + value = ["capturedWrite", "uncapturedWrite", "globalWrite", "capturedPattern"] and + location = reference.getLocation() and + ( + tag = "capturedWrite" and + exists(DataFlow::SsaDefinitionNode node | + node.getSsaVariable().getDefinition().(SsaExplicitDefinition).getLhs() = reference and + reference.getVariable().isCaptured() + ) + or + tag = "noCapturedWrite" and + not exists(DataFlow::SsaDefinitionNode node | + node.getSsaVariable().getDefinition().(SsaExplicitDefinition).getLhs() = reference and + reference.getVariable().isCaptured() + ) + ) + ) + or + tag = "ssaDefinition" and + exists(SsaExplicitDefinition definition, VarRef write, DataFlow::SsaDefinitionNode node | + write = definition.getLhs() and + write.getVariable().isCaptured() and + node = DataFlow::lvalueNode(write) and + node = DataFlow::ssaDefinitionNode(definition) and + node.getSsaVariable() = definition.getVariable() and + location = write.getLocation() and + value = write.getVariable().getName() + ) + or + tag = "noSsaAstNode" and + exists(VarDecl write | + write.getVariable().getName() = "capturedWrite" and + not exists(DataFlow::lvalueNode(write).getAstNode()) and + location = write.getLocation() and + value = write.getVariable().getName() + ) + or + tag = "localCapturedFlow" and + exists(DataFlow::InvokeNode sink, VarUse read, SsaExplicitDefinition definition | + sink.getCalleeName() = "SINK" and + sink.getArgument(0).asExpr() = read and + read.getSsaVariable().getDefinition() = definition and + definition.getSourceVariable().isCaptured() and + definition.getContainer() = sink.getContainer() and + DataFlow::lvalueNode(definition.getLhs()).getASuccessor+() = sink.getArgument(0) and + location = sink.getLocation() and + value = read.getVariable().getName() + ) + or + exists(DataFlow::InvokeNode source, DataFlow::InvokeNode sink | + source.getFile().getBaseName() = "captured.js" and + source.getCalleeName() = "SOURCE" and + sink.getCalleeName() = "SINK" and + value = source.getArgument(0).getStringValue() and + location = sink.getLocation() and + ( + tag = "capturedFlow" and CapturedFlow::flow(source, sink.getArgument(0)) + or + tag = "legacyCapturedFlow" and + any(LegacyCapturedConfig config).hasFlow(source, sink.getArgument(0)) + ) + ) + ) + } +} + +import MakeTest diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected new file mode 100644 index 000000000000..08ad3b0b1a14 --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected @@ -0,0 +1,502 @@ +nonUniqueDef +readWithoutDef +| local.js:172:9:172:24 | liveBeforeReturn | local.js:174:3:174:27 | const d ... "dead"; | 10 | +| refinement.js:449:41:449:45 | value | refinement.js:450:98:450:102 | value | 0 | +| refinement.js:454:29:454:33 | value | refinement.js:455:82:455:86 | value | 0 | +deadDef +notDominatedByDef +nonUniqueDefReachesEndOfBlock +uselessPhiNode +| namespace.ts:6:3:8:3 | SSA phi(value) | 1 | +readWithoutPriorRef +| local.js:172:9:172:24 | liveBeforeReturn | local.js:174:3:174:27 | const d ... "dead"; | 10 | +| refinement.js:449:41:449:45 | value | refinement.js:450:98:450:102 | value | 0 | +| refinement.js:454:29:454:33 | value | refinement.js:455:82:455:86 | value | 0 | +readWithMultiplePriorRefs +phiWithoutTwoPriorRefs +| namespace.ts:6:3:8:3 | SSA phi(value) | namespace.ts:6:3:8:3 | if (val ... ace\\n } | namespace.ts:2:7:2:11 | value | 1 | +phiReadWithoutTwoPriorRefs +ambiguousReadNode +nonUniqueSsaDefinition +nonUniqueSsaVariable +missingSsaNodeMetadata +| captured.js:22:10:22:24 | [ssa-use] uncapturedWrite | +| captured.js:45:1:45:23 | [ssa-use] destruc ... aration | +| captured.js:53:1:53:22 | [ssa-use] destruc ... ignment | +| captured.js:59:1:59:21 | [ssa-use] destruc ... rameter | +| captured.js:67:1:67:16 | [ssa-use] destructuredLoop | +| captured.js:73:1:73:17 | [ssa-use] destructuredArray | +| captured.js:79:1:79:18 | [ssa-use] readTopLevelObject | +| captured.js:91:1:91:15 | [ssa-use] readTopLevelPhi | +| captured.js:95:7:95:15 | [ssa-use] condition | +| captured.js:95:28:95:32 | [ssa-use] value | +| captured.js:95:36:96:3 | [ssa-synth-read] value | +| captured.js:97:5:97:9 | [ssa-use] value | +| captured.js:99:8:99:12 | [ssa-use] value | +| captured.js:104:7:104:11 | [ssa-use] value | +| captured.js:106:9:106:17 | [ssa-use] condition | +| captured.js:107:20:107:24 | [ssa-use] value | +| captured.js:108:11:108:15 | [ssa-use] value | +| captured.js:110:7:110:11 | [ssa-use] value | +| captured.js:113:8:113:12 | [ssa-use] value | +| local.js:3:7:3:15 | [ssa-use] condition | +| local.js:4:5:4:9 | [ssa-use] value | +| local.js:6:5:6:9 | [ssa-use] value | +| local.js:8:7:8:20 | [ssa-use] otherCondition | +| local.js:9:10:9:14 | [ssa-use] value | +| local.js:11:9:11:13 | [ssa-use] value | +| local.js:16:8:16:12 | [ssa-use] value | +| local.js:17:3:17:7 | [ssa-use] value | +| local.js:18:8:18:12 | [ssa-use] value | +| local.js:22:3:22:7 | [ssa-use] value | +| local.js:22:52:22:56 | [ssa-use] value | +| local.js:23:8:23:12 | [ssa-use] value | +| local.js:27:29:27:33 | [ssa-use] value | +| local.js:27:41:27:45 | [ssa-use] value | +| local.js:28:8:28:12 | [ssa-use] value | +| local.js:32:40:32:44 | [ssa-use] value | +| local.js:32:53:32:57 | [ssa-use] value | +| local.js:36:39:36:43 | [ssa-use] value | +| local.js:36:46:36:50 | [ssa-use] value | +| local.js:37:8:37:12 | [ssa-use] value | +| local.js:41:39:41:43 | [ssa-use] value | +| local.js:41:46:41:50 | [ssa-use] value | +| local.js:41:54:41:58 | [ssa-use] value | +| local.js:42:8:42:12 | [ssa-use] value | +| local.js:46:3:46:7 | [ssa-use] value | +| local.js:46:21:46:25 | [ssa-use] value | +| local.js:46:29:46:33 | [ssa-use] value | +| local.js:47:8:47:12 | [ssa-use] value | +| local.js:51:37:51:41 | [ssa-use] value | +| local.js:51:44:51:48 | [ssa-use] value | +| local.js:51:52:51:60 | [ssa-use] condition | +| local.js:51:64:51:68 | [ssa-use] value | +| local.js:52:8:52:12 | [ssa-use] value | +| local.js:56:46:56:50 | [ssa-use] value | +| local.js:56:53:56:57 | [ssa-use] value | +| local.js:60:35:60:39 | [ssa-use] value | +| local.js:60:49:60:53 | [ssa-use] value | +| local.js:61:8:61:12 | [ssa-use] value | +| local.js:65:3:65:7 | [ssa-use] value | +| local.js:66:10:66:14 | [ssa-use] value | +| local.js:69:10:69:14 | [ssa-use] value | +| local.js:71:8:71:12 | [ssa-use] value | +| local.js:75:4:75:8 | [ssa-use] value | +| local.js:75:17:75:21 | [ssa-use] value | +| local.js:75:28:75:32 | [ssa-use] value | +| local.js:76:8:76:12 | [ssa-use] value | +| local.js:81:43:81:47 | [ssa-use] value | +| local.js:83:10:83:14 | [ssa-use] value | +| local.js:85:8:85:12 | [ssa-use] value | +| local.js:90:10:90:14 | [ssa-use] value | +| local.js:91:31:91:35 | [ssa-use] value | +| local.js:92:10:92:14 | [ssa-use] value | +| local.js:98:14:98:18 | [ssa-use] value | +| local.js:100:16:100:20 | [ssa-use] value | +| local.js:102:14:102:18 | [ssa-use] value | +| local.js:106:7:106:11 | [ssa-use] value | +| local.js:107:16:107:20 | [ssa-use] value | +| local.js:108:7:108:11 | [ssa-use] value | +| local.js:109:12:109:16 | [ssa-use] value | +| local.js:115:7:115:11 | [ssa-use] value | +| local.js:116:10:116:14 | [ssa-use] value | +| local.js:117:5:117:9 | [ssa-use] value | +| local.js:118:9:118:13 | [ssa-use] value | +| local.js:119:10:119:14 | [ssa-use] value | +| local.js:124:7:124:31 | [ssa-synth-read] value | +| local.js:124:14:124:18 | [ssa-use] value | +| local.js:124:36:124:62 | [ssa-synth-read] value | +| local.js:124:43:124:47 | [ssa-use] value | +| local.js:125:10:125:14 | [ssa-use] value | +| local.js:126:5:126:9 | [ssa-use] value | +| local.js:127:9:127:13 | [ssa-use] value | +| local.js:128:10:128:14 | [ssa-use] value | +| local.js:133:7:133:11 | [ssa-use] value | +| local.js:134:5:134:9 | [ssa-use] value | +| local.js:135:16:135:20 | [ssa-use] value | +| local.js:136:12:136:16 | [ssa-use] value | +| local.js:142:7:142:11 | [ssa-synth-read] value | +| local.js:142:7:142:11 | [ssa-use] value | +| local.js:143:5:143:9 | [ssa-use] value | +| local.js:144:9:144:13 | [ssa-use] value | +| local.js:146:8:146:12 | [ssa-use] value | +| local.js:150:3:150:7 | [ssa-use] value | +| local.js:151:8:151:12 | [ssa-use] value | +| local.js:166:49:166:54 | [ssa-use] second | +| local.js:167:8:167:12 | [ssa-use] first | +| local.js:168:8:168:13 | [ssa-use] second | +| local.js:173:10:173:25 | [ssa-use] liveBeforeReturn | +| local.js:175:7:175:15 | [ssa-use] deadLocal | +| local.js:176:7:176:22 | [ssa-use] liveBeforeReturn | +| local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | +| local.js:182:11:182:14 | [ssa-use] this | +| local.js:185:9:185:17 | [ssa-use] condition | +| local.js:186:7:186:11 | [ssa-use] super | +| local.js:188:7:188:11 | [ssa-use] super | +| local.js:190:9:190:12 | [ssa-use] this | +| namespace.ts:4:5:4:9 | [ssa-use] value | +| namespace.ts:6:7:6:11 | [ssa-use] value | +| namespace.ts:7:10:7:14 | [ssa-use] value | +| nodes.js:3:7:3:15 | [ssa-use] condition | +| nodes.js:4:5:4:9 | [ssa-use] value | +| nodes.js:6:5:6:9 | [ssa-use] value | +| nodes.js:8:7:8:20 | [ssa-use] otherCondition | +| nodes.js:9:11:9:15 | [ssa-use] value | +| nodes.js:11:9:11:13 | [ssa-use] value | +| nodes.js:16:7:16:11 | [ssa-synth-read] value | +| nodes.js:16:7:16:11 | [ssa-use] value | +| nodes.js:17:5:17:9 | [ssa-use] value | +| nodes.js:19:7:19:15 | [ssa-use] condition | +| nodes.js:20:11:20:15 | [ssa-use] value | +| nodes.js:22:9:22:13 | [ssa-use] value | +| nodes.js:28:7:28:20 | [ssa-use] firstCondition | +| nodes.js:29:9:29:23 | [ssa-use] secondCondition | +| nodes.js:30:7:30:11 | [ssa-use] value | +| nodes.js:32:7:32:11 | [ssa-use] value | +| nodes.js:36:5:36:9 | [ssa-use] value | +| nodes.js:38:7:38:20 | [ssa-use] thirdCondition | +| nodes.js:39:11:39:15 | [ssa-use] value | +| nodes.js:41:9:41:13 | [ssa-use] value | +| nodes.js:47:7:47:15 | [ssa-use] condition | +| nodes.js:55:3:55:9 | [ssa-use] capture | +| nodes.js:56:7:56:20 | [ssa-use] otherCondition | +| nodes.js:64:16:64:24 | [ssa-use] parameter | +| nodes.js:66:16:66:28 | [ssa-use] uninitialized | +| nodes.js:67:30:67:38 | [ssa-use] parameter | +| nodes.js:68:16:68:20 | [ssa-use] value | +| nodes.js:69:14:69:18 | [ssa-use] value | +| nodes.js:70:18:70:22 | [ssa-use] value | +| nodes.js:85:3:85:7 | [ssa-use] write | +| nodes.js:87:10:87:13 | [ssa-use] read | +| refinement.js:3:8:3:30 | [ssa-use] refinem ... rSource | +| refinement.js:4:10:4:32 | [ssa-use] refinem ... rSource | +| refinement.js:10:16:10:21 | [ssa-use] object | +| refinement.js:10:23:10:25 | [ssa-use] key | +| refinement.js:11:8:11:13 | [ssa-use] object | +| refinement.js:11:15:11:17 | [ssa-use] key | +| refinement.js:12:8:12:13 | [ssa-use] object | +| refinement.js:13:3:13:5 | [ssa-use] key | +| refinement.js:14:8:14:13 | [ssa-use] object | +| refinement.js:14:15:14:17 | [ssa-use] key | +| refinement.js:19:7:19:19 | [ssa-use] phiReadSource | +| refinement.js:20:9:20:17 | [ssa-use] condition | +| refinement.js:21:12:21:33 | [ssa-synth-read] phiReadSource | +| refinement.js:21:20:21:32 | [ssa-use] phiReadSource | +| refinement.js:23:12:23:33 | [ssa-synth-read] phiReadSource | +| refinement.js:23:20:23:32 | [ssa-use] phiReadSource | +| refinement.js:25:10:25:22 | [ssa-use] phiReadSource | +| refinement.js:31:8:31:26 | [ssa-use] refinementPhiSource | +| refinement.js:32:9:32:17 | [ssa-synth-read] refinementPhiSource | +| refinement.js:32:9:32:17 | [ssa-use] condition | +| refinement.js:33:7:33:25 | [ssa-use] refinementPhiSource | +| refinement.js:35:10:35:28 | [ssa-use] refinementPhiSource | +| refinement.js:41:7:41:11 | [ssa-use] value | +| refinement.js:41:7:41:19 | [ssa-synth-read] value | +| refinement.js:41:24:41:28 | [ssa-use] value | +| refinement.js:41:24:41:36 | [ssa-synth-read] value | +| refinement.js:42:10:42:14 | [ssa-use] value | +| refinement.js:48:7:48:11 | [ssa-use] value | +| refinement.js:48:7:48:19 | [ssa-synth-read] value | +| refinement.js:48:24:48:28 | [ssa-use] value | +| refinement.js:48:24:48:36 | [ssa-synth-read] value | +| refinement.js:48:39:55:3 | [ssa-synth-read] value | +| refinement.js:49:9:49:17 | [ssa-use] condition | +| refinement.js:50:11:50:15 | [ssa-use] value | +| refinement.js:52:11:52:15 | [ssa-use] value | +| refinement.js:54:10:54:14 | [ssa-use] value | +| refinement.js:59:7:59:11 | [ssa-synth-read] value | +| refinement.js:59:7:59:11 | [ssa-use] value | +| refinement.js:60:5:60:9 | [ssa-use] value | +| refinement.js:62:8:62:12 | [ssa-use] value | +| refinement.js:66:8:66:12 | [ssa-use] value | +| refinement.js:67:9:67:17 | [ssa-synth-read] value | +| refinement.js:67:9:67:17 | [ssa-use] condition | +| refinement.js:68:7:68:11 | [ssa-use] value | +| refinement.js:70:10:70:14 | [ssa-use] value | +| refinement.js:75:7:75:11 | [ssa-synth-read] value | +| refinement.js:75:7:75:11 | [ssa-use] value | +| refinement.js:76:5:76:9 | [ssa-use] value | +| refinement.js:78:7:78:15 | [ssa-use] condition | +| refinement.js:79:5:79:9 | [ssa-use] value | +| refinement.js:81:8:81:12 | [ssa-use] value | +| refinement.js:85:7:85:11 | [ssa-synth-read] value | +| refinement.js:85:7:85:11 | [ssa-use] value | +| refinement.js:86:5:86:9 | [ssa-use] value | +| refinement.js:88:7:88:15 | [ssa-use] condition | +| refinement.js:89:9:89:13 | [ssa-use] value | +| refinement.js:91:9:91:13 | [ssa-use] value | +| refinement.js:93:8:93:12 | [ssa-use] value | +| refinement.js:98:8:98:12 | [ssa-use] value | +| refinement.js:99:9:99:17 | [ssa-synth-read] value | +| refinement.js:99:9:99:17 | [ssa-use] condition | +| refinement.js:100:7:100:11 | [ssa-use] value | +| refinement.js:102:9:102:22 | [ssa-use] otherCondition | +| refinement.js:103:12:103:16 | [ssa-use] value | +| refinement.js:105:12:105:16 | [ssa-use] value | +| refinement.js:111:9:111:13 | [ssa-use] value | +| refinement.js:112:10:112:14 | [ssa-use] value | +| refinement.js:117:9:117:22 | [ssa-use] firstCondition | +| refinement.js:118:11:118:25 | [ssa-use] secondCondition | +| refinement.js:119:9:119:13 | [ssa-use] value | +| refinement.js:121:9:121:13 | [ssa-use] value | +| refinement.js:125:7:125:11 | [ssa-use] value | +| refinement.js:127:10:127:14 | [ssa-use] value | +| refinement.js:132:9:132:22 | [ssa-use] firstCondition | +| refinement.js:133:11:133:25 | [ssa-use] secondCondition | +| refinement.js:134:9:134:13 | [ssa-use] value | +| refinement.js:136:9:136:13 | [ssa-use] value | +| refinement.js:140:7:140:11 | [ssa-use] value | +| refinement.js:142:9:142:22 | [ssa-use] thirdCondition | +| refinement.js:143:12:143:16 | [ssa-use] value | +| refinement.js:145:11:145:15 | [ssa-use] value | +| refinement.js:151:9:151:13 | [ssa-use] value | +| refinement.js:152:11:152:19 | [ssa-use] condition | +| refinement.js:153:14:153:27 | [ssa-synth-read] value | +| refinement.js:153:22:153:26 | [ssa-use] value | +| refinement.js:155:14:155:27 | [ssa-synth-read] value | +| refinement.js:155:22:155:26 | [ssa-use] value | +| refinement.js:157:18:157:22 | [ssa-use] value | +| refinement.js:158:14:158:18 | [ssa-use] value | +| refinement.js:165:10:165:14 | [ssa-use] value | +| refinement.js:166:11:166:19 | [ssa-synth-read] value | +| refinement.js:166:11:166:19 | [ssa-use] condition | +| refinement.js:167:13:167:17 | [ssa-use] value | +| refinement.js:169:12:169:16 | [ssa-use] value | +| refinement.js:175:9:175:17 | [ssa-use] condition | +| refinement.js:175:20:176:5 | [ssa-synth-read] value | +| refinement.js:176:16:176:20 | [ssa-synth-read] value | +| refinement.js:176:16:176:20 | [ssa-use] value | +| refinement.js:177:7:177:11 | [ssa-use] value | +| refinement.js:179:9:179:22 | [ssa-use] otherCondition | +| refinement.js:180:12:180:16 | [ssa-use] value | +| refinement.js:182:11:182:15 | [ssa-use] value | +| refinement.js:188:18:188:22 | [ssa-use] value | +| refinement.js:189:10:189:14 | [ssa-use] value | +| refinement.js:194:28:194:32 | [ssa-use] value | +| refinement.js:195:10:195:14 | [ssa-use] value | +| refinement.js:200:9:200:17 | [ssa-use] condition | +| refinement.js:201:20:201:24 | [ssa-use] value | +| refinement.js:203:20:203:24 | [ssa-use] value | +| refinement.js:205:10:205:14 | [ssa-use] value | +| refinement.js:210:17:210:21 | [ssa-use] value | +| refinement.js:211:10:211:14 | [ssa-use] value | +| refinement.js:216:24:216:28 | [ssa-use] value | +| refinement.js:217:9:217:10 | [ssa-use] ok | +| refinement.js:218:11:218:15 | [ssa-use] value | +| refinement.js:220:7:220:11 | [ssa-use] value | +| refinement.js:222:10:222:14 | [ssa-use] value | +| refinement.js:227:24:227:28 | [ssa-use] value | +| refinement.js:228:9:228:10 | [ssa-use] ok | +| refinement.js:228:13:229:5 | [ssa-synth-read] value | +| refinement.js:230:7:230:11 | [ssa-use] value | +| refinement.js:232:10:232:14 | [ssa-use] value | +| refinement.js:237:24:237:28 | [ssa-use] value | +| refinement.js:238:16:238:20 | [ssa-use] value | +| refinement.js:239:11:239:12 | [ssa-use] ok | +| refinement.js:239:15:240:7 | [ssa-synth-read] value | +| refinement.js:241:9:241:13 | [ssa-use] value | +| refinement.js:243:12:243:16 | [ssa-use] value | +| refinement.js:249:11:249:21 | [ssa-use] scopeObject | +| refinement.js:250:19:250:23 | [ssa-use] value | +| refinement.js:251:13:251:17 | [ssa-use] value | +| refinement.js:253:9:253:13 | [ssa-use] value | +| refinement.js:256:10:256:14 | [ssa-use] value | +| refinement.js:260:5:260:10 | [ssa-use] target | +| refinement.js:260:23:260:29 | [ssa-use] payload | +| refinement.js:264:29:264:33 | [ssa-use] value | +| refinement.js:264:70:264:74 | [ssa-use] value | +| refinement.js:264:78:264:82 | [ssa-use] value | +| refinement.js:265:10:265:14 | [ssa-use] value | +| refinement.js:269:29:269:33 | [ssa-use] value | +| refinement.js:269:37:269:41 | [ssa-use] value | +| refinement.js:269:53:269:57 | [ssa-use] value | +| refinement.js:270:10:270:14 | [ssa-use] value | +| refinement.js:274:5:274:9 | [ssa-use] value | +| refinement.js:274:23:274:27 | [ssa-use] value | +| refinement.js:274:31:274:35 | [ssa-use] value | +| refinement.js:275:10:275:14 | [ssa-use] value | +| refinement.js:279:19:279:23 | [ssa-use] value | +| refinement.js:280:29:280:33 | [ssa-use] value | +| refinement.js:280:63:280:67 | [ssa-use] value | +| refinement.js:280:71:280:75 | [ssa-use] alias | +| refinement.js:281:10:281:14 | [ssa-use] value | +| refinement.js:285:29:285:33 | [ssa-use] value | +| refinement.js:285:73:285:77 | [ssa-use] value | +| refinement.js:285:81:285:89 | [ssa-use] condition | +| refinement.js:285:93:285:97 | [ssa-use] value | +| refinement.js:286:10:286:14 | [ssa-use] value | +| refinement.js:290:29:290:33 | [ssa-use] value | +| refinement.js:290:69:290:73 | [ssa-use] value | +| refinement.js:290:77:290:85 | [ssa-use] condition | +| refinement.js:290:89:290:93 | [ssa-use] value | +| refinement.js:290:97:290:101 | [ssa-use] value | +| refinement.js:291:10:291:14 | [ssa-use] value | +| refinement.js:295:29:295:33 | [ssa-use] value | +| refinement.js:295:72:295:76 | [ssa-use] value | +| refinement.js:295:80:295:84 | [ssa-use] value | +| refinement.js:296:10:296:14 | [ssa-use] value | +| refinement.js:300:29:300:33 | [ssa-use] value | +| refinement.js:300:72:300:76 | [ssa-use] value | +| refinement.js:300:80:300:84 | [ssa-use] value | +| refinement.js:301:10:301:14 | [ssa-use] value | +| refinement.js:305:29:305:33 | [ssa-use] value | +| refinement.js:305:68:305:72 | [ssa-use] value | +| refinement.js:305:76:305:84 | [ssa-use] condition | +| refinement.js:305:89:305:93 | [ssa-use] value | +| refinement.js:306:10:306:14 | [ssa-use] value | +| refinement.js:310:29:310:33 | [ssa-use] value | +| refinement.js:310:70:310:74 | [ssa-use] value | +| refinement.js:310:78:310:86 | [ssa-use] condition | +| refinement.js:310:98:310:102 | [ssa-use] value | +| refinement.js:310:107:310:111 | [ssa-use] value | +| refinement.js:311:10:311:14 | [ssa-use] value | +| refinement.js:315:19:315:27 | [ssa-use] condition | +| refinement.js:315:31:315:35 | [ssa-use] value | +| refinement.js:315:39:315:40 | [ssa-synth-read] value | +| refinement.js:316:29:316:33 | [ssa-use] value | +| refinement.js:316:74:316:78 | [ssa-use] value | +| refinement.js:316:82:316:86 | [ssa-use] alias | +| refinement.js:317:10:317:14 | [ssa-use] value | +| refinement.js:321:5:321:9 | [ssa-use] value | +| refinement.js:321:23:321:27 | [ssa-use] value | +| refinement.js:321:31:321:39 | [ssa-use] condition | +| refinement.js:321:43:321:47 | [ssa-use] value | +| refinement.js:322:10:322:14 | [ssa-use] value | +| refinement.js:326:29:326:33 | [ssa-use] value | +| refinement.js:326:71:326:75 | [ssa-use] value | +| refinement.js:326:79:326:83 | [ssa-use] value | +| refinement.js:327:10:327:14 | [ssa-use] value | +| refinement.js:331:29:331:33 | [ssa-use] value | +| refinement.js:331:75:331:79 | [ssa-use] value | +| refinement.js:331:84:331:88 | [ssa-use] value | +| refinement.js:332:10:332:14 | [ssa-use] value | +| refinement.js:336:12:336:16 | [ssa-use] value | +| refinement.js:344:29:344:33 | [ssa-use] value | +| refinement.js:344:73:344:77 | [ssa-use] value | +| refinement.js:344:83:344:87 | [ssa-use] value | +| refinement.js:345:10:345:14 | [ssa-use] value | +| refinement.js:349:29:349:33 | [ssa-use] value | +| refinement.js:349:81:349:85 | [ssa-use] value | +| refinement.js:349:99:349:103 | [ssa-use] value | +| refinement.js:350:10:350:14 | [ssa-use] value | +| refinement.js:354:29:354:33 | [ssa-use] value | +| refinement.js:354:67:354:71 | [ssa-use] value | +| refinement.js:354:84:354:88 | [ssa-use] value | +| refinement.js:355:10:355:14 | [ssa-use] value | +| refinement.js:359:29:359:33 | [ssa-use] value | +| refinement.js:359:66:359:70 | [ssa-use] value | +| refinement.js:359:75:359:79 | [ssa-use] value | +| refinement.js:360:10:360:14 | [ssa-use] value | +| refinement.js:364:29:364:33 | [ssa-use] value | +| refinement.js:364:66:364:70 | [ssa-use] value | +| refinement.js:364:100:364:104 | [ssa-use] value | +| refinement.js:365:10:365:14 | [ssa-use] value | +| refinement.js:370:7:370:11 | [ssa-use] value | +| refinement.js:370:46:370:50 | [ssa-use] value | +| refinement.js:370:80:370:84 | [ssa-use] value | +| refinement.js:371:12:371:16 | [ssa-use] value | +| refinement.js:373:10:373:14 | [ssa-use] value | +| refinement.js:377:29:377:33 | [ssa-use] value | +| refinement.js:377:73:377:77 | [ssa-use] value | +| refinement.js:377:110:377:114 | [ssa-use] value | +| refinement.js:378:10:378:14 | [ssa-use] value | +| refinement.js:382:29:382:33 | [ssa-use] value | +| refinement.js:382:83:382:87 | [ssa-use] value | +| refinement.js:383:10:383:14 | [ssa-use] value | +| refinement.js:387:29:387:33 | [ssa-use] value | +| refinement.js:387:74:387:78 | [ssa-use] value | +| refinement.js:388:10:388:14 | [ssa-use] value | +| refinement.js:393:7:393:11 | [ssa-use] value | +| refinement.js:393:48:393:52 | [ssa-use] value | +| refinement.js:393:84:393:88 | [ssa-use] value | +| refinement.js:395:10:395:14 | [ssa-use] value | +| refinement.js:400:24:400:28 | [ssa-use] input | +| refinement.js:402:29:402:33 | [ssa-use] value | +| refinement.js:402:76:402:80 | [ssa-use] value | +| refinement.js:402:84:402:87 | [ssa-use] wrap | +| refinement.js:402:89:402:93 | [ssa-use] value | +| refinement.js:403:10:403:14 | [ssa-use] value | +| refinement.js:407:29:407:33 | [ssa-use] value | +| refinement.js:407:66:407:70 | [ssa-use] value | +| refinement.js:407:80:407:84 | [ssa-use] value | +| refinement.js:408:10:408:14 | [ssa-use] value | +| refinement.js:412:29:412:33 | [ssa-use] value | +| refinement.js:412:71:412:75 | [ssa-use] value | +| refinement.js:412:85:412:89 | [ssa-use] value | +| refinement.js:413:10:413:14 | [ssa-use] value | +| refinement.js:418:29:418:33 | [ssa-use] value | +| refinement.js:418:63:418:67 | [ssa-use] value | +| refinement.js:418:89:418:93 | [ssa-use] value | +| refinement.js:419:10:419:14 | [ssa-use] value | +| refinement.js:424:29:424:33 | [ssa-use] value | +| refinement.js:424:71:424:75 | [ssa-use] value | +| refinement.js:424:79:424:83 | [ssa-use] clone | +| refinement.js:424:85:424:89 | [ssa-use] value | +| refinement.js:425:10:425:14 | [ssa-use] value | +| refinement.js:430:7:430:11 | [ssa-use] value | +| refinement.js:431:7:431:11 | [ssa-use] value | +| refinement.js:431:15:431:23 | [ssa-use] condition | +| refinement.js:431:34:431:38 | [ssa-use] value | +| refinement.js:431:72:431:76 | [ssa-use] value | +| refinement.js:433:10:433:14 | [ssa-use] value | +| refinement.js:438:7:438:11 | [ssa-use] value | +| refinement.js:439:7:439:11 | [ssa-use] value | +| refinement.js:439:15:439:23 | [ssa-use] condition | +| refinement.js:439:34:439:38 | [ssa-use] value | +| refinement.js:439:72:439:76 | [ssa-use] value | +| refinement.js:441:10:441:14 | [ssa-use] value | +| refinement.js:445:29:445:33 | [ssa-use] value | +| refinement.js:445:72:445:76 | [ssa-use] value | +| refinement.js:445:94:445:98 | [ssa-use] value | +| refinement.js:446:10:446:14 | [ssa-use] value | +| refinement.js:450:29:450:33 | [ssa-use] value | +| refinement.js:450:78:450:82 | [ssa-use] value | +| refinement.js:450:98:450:102 | [ssa-use] value | +| refinement.js:451:10:451:14 | [ssa-use] value | +| refinement.js:455:29:455:33 | [ssa-use] value | +| refinement.js:455:65:455:69 | [ssa-use] value | +| refinement.js:455:82:455:86 | [ssa-use] value | +| refinement.js:456:10:456:14 | [ssa-use] value | +| refinement.js:460:29:460:33 | [ssa-use] value | +| refinement.js:460:65:460:69 | [ssa-use] value | +| refinement.js:461:10:461:14 | [ssa-use] value | +| refinement.js:465:5:465:9 | [ssa-use] value | +| refinement.js:465:23:465:27 | [ssa-use] value | +| refinement.js:466:10:466:14 | [ssa-use] value | +| refinement.js:470:17:470:21 | [ssa-use] value | +| refinement.js:471:5:471:9 | [ssa-use] alias | +| refinement.js:472:29:472:33 | [ssa-use] value | +| refinement.js:472:75:472:79 | [ssa-use] value | +| refinement.js:472:83:472:87 | [ssa-use] alias | +| refinement.js:473:10:473:14 | [ssa-use] value | +| refinement.js:478:11:478:19 | [ssa-use] condition | +| refinement.js:479:14:479:26 | [ssa-synth-read] this | +| refinement.js:479:22:479:25 | [ssa-use] this | +| refinement.js:481:14:481:26 | [ssa-synth-read] this | +| refinement.js:481:22:481:25 | [ssa-use] this | +| refinement.js:483:12:483:15 | [ssa-use] this | +| refinement.js:487:7:487:10 | [ssa-use] this | +| refinement.js:488:20:488:23 | [ssa-use] this | +| refinement.js:489:20:489:23 | [ssa-use] this | +| refinement.js:490:12:490:15 | [ssa-use] this | +| tst.js:4:5:4:26 | [ssa-use] compati ... iSource | +| tst.js:4:30:4:34 | [ssa-use] start | +| tst.js:5:5:5:26 | [ssa-use] compati ... iSource | +| tst.js:5:30:5:32 | [ssa-use] end | +| tst.js:6:5:6:26 | [ssa-use] compati ... iSource | +| tst.js:6:5:6:28 | [ssa-synth-read] end | +| tst.js:9:8:9:29 | [ssa-use] compati ... iSource | +orphanSsaDefinitionNode +ssaDefinitionHasAstNode +unmappedWriteDefSourceNode +nonUniqueSharedSsaNodeMapping +| local.js:186:7:186:11 | super [postupdate] | 2 | +| local.js:188:7:188:11 | super [postupdate] | 2 | +sharedReadContainerMismatch +postUpdateMustFlow +localFlowIsLocal +| local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | local.js:182:3:182:33 | implicit 'this' | Local flow step does not preserve enclosing callable. | +| local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | local.js:190:9:190:12 | [ssa-use] this | Local flow step does not preserve enclosing callable. | +| local.js:182:11:182:14 | [post update] this | local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | Local flow step does not preserve enclosing callable. | +| local.js:182:11:182:14 | [ssa-use] this | local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | Local flow step does not preserve enclosing callable. | +| local.js:190:9:190:12 | [ssa-use] this | local.js:190:9:190:12 | this | Local flow step does not preserve enclosing callable. | diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql new file mode 100644 index 000000000000..edf1b59d40cd --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql @@ -0,0 +1,62 @@ +import javascript +import semmle.javascript.dataflow.internal.DataFlowNode +import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate +import semmle.javascript.dataflow.internal.DataFlowImplConsistency as DataFlowImplConsistency +import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2 +import Ssa2::Consistency +import Ssa2::DfConsistency + +query predicate localFlowIsLocal = DataFlowImplConsistency::Consistency::localFlowIsLocal/3; + +query predicate nonUniqueSsaDefinition(SsaDefinition definition, int nodes) { + nodes = count(DataFlow::ssaDefinitionNode(definition)) and + nodes != 1 +} + +query predicate nonUniqueSsaVariable(DataFlow::SsaDefinitionNode node, int variables) { + variables = count(node.getSsaVariable()) and + variables != 1 +} + +query predicate missingSsaNodeMetadata(DataFlow::Node node) { + ( + node instanceof TSsaDefNode or + node instanceof TSsaUseNode or + node instanceof TSsaSynthReadNode + ) and + not ( + exists(node.toString()) and + (exists(node.getBasicBlock()) or node instanceof TSsaUseNode) and + exists(node.getContainer()) and + exists(node.getLocation()) and + exists(node.getFile()) + ) +} + +query predicate orphanSsaDefinitionNode(DataFlow::Node node) { + node instanceof TSsaDefNode and + not node instanceof DataFlow::SsaDefinitionNode +} + +query predicate ssaDefinitionHasAstNode(DataFlow::SsaDefinitionNode node, AstNode ast) { + ast = node.getAstNode() +} + +query predicate unmappedWriteDefSourceNode(Ssa2::WriteDefSourceNode node, int mapped) { + mapped = count(DataFlowPrivate::getNodeFromSsa2(node)) and + mapped != 1 +} + +query predicate nonUniqueSharedSsaNodeMapping(Ssa2::Node node, int mapped) { + mapped = count(DataFlowPrivate::getNodeFromSsa2(node)) and + mapped > 1 +} + +query predicate sharedReadContainerMismatch(Ssa2::ExprNode read) { + TSsaUseNode(read.getExpr()).(DataFlow::Node).getContainer() != + DataFlowPrivate::getNodeFromSsa2(read).(DataFlow::Node).getContainer() +} + +query predicate postUpdateMustFlow(DataFlow::PostUpdateNode update, DataFlow::Node node) { + node.getImmediatePredecessor() = update +} diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/local.expected b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/local.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.js new file mode 100644 index 000000000000..5bc3a3ffa56e --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.js @@ -0,0 +1,192 @@ +function ordinaryPhiLocalFlow(condition, otherCondition) { + let value; + if (condition) { + value = SOURCE("ordinary-phi"); + } else { + value = {}; + } + if (otherCondition) { + SINK(value); // $ localFlow=ordinary-phi + } else { + use(value); + } +} + +function postUpdateOrdering(value) { + SINK(value); // $ noPostUpdateFlow=post-update + value.property = SOURCE("post-update"); + SINK(value); // $ SPURIOUS: noPostUpdateFlow=post-update MISSING: postUpdateFlow=post-update +} + +function assignmentUpdateCompletion(value) { + value.property = SOURCE("store-completion", SINK(value)); // $ noPostUpdateFlow=store-completion SPURIOUS: globalPostUpdateFlow=store-completion MISSING: noGlobalPostUpdateFlow=store-completion + SINK(value); // $ globalPostUpdateFlow=store-completion SPURIOUS: noPostUpdateFlow=store-completion MISSING: postUpdateFlow=store-completion +} + +function callUpdateCompletion(value) { + UPDATE("call-completion", value, SINK(value)); // $ noPostUpdateFlow=call-completion SPURIOUS: globalPostUpdateFlow=call-completion MISSING: noGlobalPostUpdateFlow=call-completion + SINK(value); // $ globalPostUpdateFlow=call-completion SPURIOUS: noPostUpdateFlow=call-completion MISSING: postUpdateFlow=call-completion +} + +function nestedCallUpdateCompletion(value) { + use(UPDATE("nested-call-completion", value), SINK(value)); // $ globalPostUpdateFlow=nested-call-completion SPURIOUS: noPostUpdateFlow=nested-call-completion MISSING: postUpdateFlow=nested-call-completion +} + +function overwrittenCallArgument(value) { + UPDATE("overwritten-call-argument", value, value = {}); + SINK(value); // $ noPostUpdateFlow=overwritten-call-argument noGlobalPostUpdateFlow=overwritten-call-argument +} + +function selfAssignedCallUpdate(value) { + UPDATE("self-assigned-call-update", value, value = value); + SINK(value); // $ globalPostUpdateFlow=self-assigned-call-update SPURIOUS: noPostUpdateFlow=self-assigned-call-update MISSING: postUpdateFlow=self-assigned-call-update +} + +function selfAssignedStoreUpdate(value) { + value.property = (value = value, SOURCE("self-assigned-store-update")); + SINK(value); // $ globalPostUpdateFlow=self-assigned-store-update SPURIOUS: noPostUpdateFlow=self-assigned-store-update MISSING: postUpdateFlow=self-assigned-store-update +} + +function conditionalCallUpdate(value, condition) { + UPDATE("conditional-call-update", value, value = condition ? value : {}); + SINK(value); // $ globalPostUpdateFlow=conditional-call-update SPURIOUS: noPostUpdateFlow=conditional-call-update MISSING: postUpdateFlow=conditional-call-update +} + +function unusedOverwrittenCallArgument(value) { + UPDATE("unused-overwritten-call-argument", value, value = {}); +} + +function refinedCallArgument(value) { + UPDATE("refined-call-argument", value, typeof value === "object" ? 1 : 2); + SINK(value); // $ globalPostUpdateFlow=refined-call-argument SPURIOUS: noPostUpdateFlow=refined-call-argument MISSING: postUpdateFlow=refined-call-argument +} + +function computedStoreCompletion(value) { + value[ + SINK(value) // $ noPostUpdateFlow=computed-store-completion SPURIOUS: globalPostUpdateFlow=computed-store-completion MISSING: noGlobalPostUpdateFlow=computed-store-completion + ] = SOURCE( + "computed-store-completion", + SINK(value) // $ noPostUpdateFlow=computed-store-completion SPURIOUS: globalPostUpdateFlow=computed-store-completion MISSING: noGlobalPostUpdateFlow=computed-store-completion + ); + SINK(value); // $ globalPostUpdateFlow=computed-store-completion SPURIOUS: noPostUpdateFlow=computed-store-completion MISSING: postUpdateFlow=computed-store-completion +} + +function destructuringStoreCompletion(value) { + [value.first, value[SINK(value)]] = SOURCE("destructuring-store-completion"); // $ globalPostUpdateFlow=destructuring-store-completion SPURIOUS: noPostUpdateFlow=destructuring-store-completion MISSING: postUpdateFlow=destructuring-store-completion + SINK(value); // $ globalPostUpdateFlow=destructuring-store-completion SPURIOUS: noPostUpdateFlow=destructuring-store-completion MISSING: postUpdateFlow=destructuring-store-completion +} + +function exceptionalCallUpdate(value) { + try { + UPDATE("exceptional-call-completion", value); + } catch (error) { + SINK(value); // $ globalPostUpdateFlow=exceptional-call-completion SPURIOUS: noPostUpdateFlow=exceptional-call-completion MISSING: postUpdateFlow=exceptional-call-completion + } + SINK(value); // $ globalPostUpdateFlow=exceptional-call-completion SPURIOUS: noPostUpdateFlow=exceptional-call-completion MISSING: postUpdateFlow=exceptional-call-completion +} + +function loopUpdateCompletion(value) { + while (condition()) { + SINK(value); // $ globalPostUpdateFlow=loop-completion SPURIOUS: noPostUpdateFlow=loop-completion MISSING: postUpdateFlow=loop-completion + UPDATE("loop-completion", value); + SINK(value); // $ globalPostUpdateFlow=loop-completion SPURIOUS: noPostUpdateFlow=loop-completion MISSING: postUpdateFlow=loop-completion + } +} + +function reflectiveReadInference() { + const value = () => 42; + CHECK_TYPE(value); // $ noReflectiveValue + with ({}) { + CHECK_TYPE(value); // $ reflectiveValue + } + CHECK_TYPE(value); // $ noReflectiveValue +} + +function nestedRefinementPostUpdate(value) { + if (value) { + if (typeof value === "object") { + value.property = SOURCE("nested-post-update"); + SINK(value); // $ SPURIOUS: noPostUpdateFlow=nested-post-update MISSING: postUpdateFlow=nested-post-update + } + } +} + +function refinedPostUpdateReads(value) { + if (value) { + SINK(value); // $ noPostUpdateFlow=refined-post-update + value.property = SOURCE("refined-post-update"); + use(value); + SINK(value); // $ SPURIOUS: noPostUpdateFlow=refined-post-update MISSING: postUpdateFlow=refined-post-update + } +} + +function compatibilityPhiPostUpdateReads(value) { + if (typeof value === "object" || typeof value === "function") { + SINK(value); // $ noPostUpdateFlow=compatibility-phi-post-update + value.property = SOURCE("compatibility-phi-post-update"); + use(value); + SINK(value); // $ SPURIOUS: noPostUpdateFlow=compatibility-phi-post-update MISSING: postUpdateFlow=compatibility-phi-post-update + } +} + +function postUpdateBeforeNestedRefinement(value) { + if (value) { + value.property = SOURCE("update-before-refinement"); + if (typeof value === "object") { + SINK(value); // $ SPURIOUS: noPostUpdateFlow=update-before-refinement MISSING: postUpdateFlow=update-before-refinement + } + } +} + +function postUpdateBeforeCompatibilityPhi(value) { + if (value) { + value.property = SOURCE("update-before-phi"); + use(value); + } + SINK(value); // $ SPURIOUS: noPostUpdateFlow=update-before-phi MISSING: postUpdateFlow=update-before-phi +} + +function postUpdateImmediatePredecessor(value) { + value.property = SOURCE("update-immediate-predecessor"); + SINK(value); // $ noImmediatePostUpdate=update-immediate-predecessor SPURIOUS: noPostUpdateFlow=update-immediate-predecessor MISSING: postUpdateFlow=update-immediate-predecessor +} + +function capturedRefinementLocalFlow() { + const value = SOURCE("captured-refinement"); + function capture() { + use(value); + } + if (value) { + if (typeof value === "object") { + SINK(value); // $ localFlow=captured-refinement + } + } +} + +function parameterReadBeforeDeclaration(first = second, second = SOURCE("later-parameter")) { + SINK(first); + SINK(second); // $ localFlow=later-parameter +} + +function unreachableLocalSsaCode() { + const liveBeforeReturn = "safe"; + return liveBeforeReturn; + const deadLocal = "dead"; + use(deadLocal); + use(liveBeforeReturn); +} + +class SharedSsaBase {} + +class SharedSsaDerived extends SharedSsaBase { + field = this.condition ? 1 : 2; // $ SPURIOUS: fieldReadContainerMismatch + + constructor(condition) { + if (condition) { + super(); // $ noSuperFlow noThisSelfFlow + } else { + super(); // $ noSuperFlow noThisSelfFlow + } + use(this); + } +} diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql new file mode 100644 index 000000000000..fda73fc7f6fb --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql @@ -0,0 +1,160 @@ +import javascript +import semmle.javascript.dataflow.internal.DataFlowNode +import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2 +import utils.test.InlineExpectationsTest + +private DataFlow::PostUpdateNode postUpdateForSource(string value) { + exists(Assignment assignment, PropAccess property, DataFlow::InvokeNode source | + ( + assignment.getTarget() = property + or + assignment.getTarget().(ArrayPattern).getElement(0) = property + ) and + assignment.getRhs().getUnderlyingValue() = source.asExpr() and + source.getCalleeName() = "SOURCE" and + source.getArgument(0).getStringValue() = value and + result.getPreUpdateNode() = DataFlow::valueNode(property.getBase()) + ) + or + exists(DataFlow::InvokeNode call | + call.getCalleeName() = "UPDATE" and + call.getArgument(0).getStringValue() = value and + result.getPreUpdateNode() = call.getArgument(1) + ) +} + +module PostUpdateConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source = postUpdateForSource(_) } + + predicate isSink(DataFlow::Node sink) { + sink = any(DataFlow::InvokeNode call | call.getCalleeName() = "SINK").getArgument(0) + } +} + +module PostUpdateFlow = DataFlow::Global; + +module InlineTest implements TestSig { + string getARelevantTag() { + result = + [ + "localFlow", "postUpdateFlow", "noPostUpdateFlow", "noImmediatePostUpdate", "noSuperFlow", + "noThisSelfFlow", "superPostUpdateToThisFlow", "fieldReadContainerMismatch", + "globalPostUpdateFlow", "noGlobalPostUpdateFlow", "reflectiveValue", "noReflectiveValue" + ] + } + + predicate hasActualResult(Location location, string element, string tag, string value) { + element = "" and + location.getFile().getBaseName() = "local.js" and + ( + tag = "localFlow" and + exists(DataFlow::InvokeNode source, DataFlow::InvokeNode sink | + source.getCalleeName() = "SOURCE" and + value = source.getArgument(0).getStringValue() and + sink.getCalleeName() = "SINK" and + source.getContainer() = sink.getContainer() and + source.flowsTo(sink.getArgument(0)) and + location = sink.getLocation() + ) + or + tag = "postUpdateFlow" and + exists(DataFlow::InvokeNode sink, DataFlow::PostUpdateNode update | + sink.getCalleeName() = "SINK" and + update = postUpdateForSource(value) and + update.getContainer() = sink.getContainer() and + update.getASuccessor+() = sink.getArgument(0) and + location = sink.getLocation() + ) + or + tag = "noPostUpdateFlow" and + exists(DataFlow::InvokeNode sink, DataFlow::PostUpdateNode update | + sink.getCalleeName() = "SINK" and + update = postUpdateForSource(value) and + update.getContainer() = sink.getContainer() and + not update.getASuccessor+() = sink.getArgument(0) and + location = sink.getLocation() + ) + or + exists(DataFlow::InvokeNode sink, DataFlow::PostUpdateNode update | + value = + [ + "store-completion", "call-completion", "nested-call-completion", + "overwritten-call-argument", "loop-completion", "refined-call-argument", + "computed-store-completion", "exceptional-call-completion", + "destructuring-store-completion", "self-assigned-call-update", + "self-assigned-store-update", "conditional-call-update" + ] and + sink.getCalleeName() = "SINK" and + update = postUpdateForSource(value) and + update.getContainer() = sink.getContainer() and + location = sink.getLocation() and + ( + tag = "globalPostUpdateFlow" and PostUpdateFlow::flow(update, sink.getArgument(0)) + or + tag = "noGlobalPostUpdateFlow" and not PostUpdateFlow::flow(update, sink.getArgument(0)) + ) + ) + or + exists(DataFlow::InvokeNode call | + call.getCalleeName() = "CHECK_TYPE" and + location = call.getLocation() and + value = "" and + ( + tag = "reflectiveValue" and + call.getArgument(0).analyze().getALocalValue().isIndefinite("eval") + or + tag = "noReflectiveValue" and + not call.getArgument(0).analyze().getALocalValue().isIndefinite("eval") + ) + ) + or + tag = "noImmediatePostUpdate" and + value = "update-immediate-predecessor" and + exists(DataFlow::InvokeNode sink, DataFlow::PostUpdateNode update | + sink.getCalleeName() = "SINK" and + update = postUpdateForSource(value) and + update.getContainer() = sink.getContainer() and + not sink.getArgument(0).getImmediatePredecessor() = update and + location = sink.getLocation() + ) + or + tag = "noSuperFlow" and + value = "" and + exists(SuperCall call, Function constructor | + constructor = call.getEnclosingFunction() and + not DataFlow::thisNode(constructor).flowsTo(DataFlow::valueNode(call.getCallee())) and + location = call.getLocation() + ) + or + tag = "noThisSelfFlow" and + value = "" and + exists(SuperCall call, Function constructor, DataFlow::ThisNode thisNode | + constructor = call.getEnclosingFunction() and + thisNode = DataFlow::thisNode(constructor) and + not thisNode.getASuccessor() = thisNode and + location = call.getLocation() + ) + or + tag = "superPostUpdateToThisFlow" and + value = "" and + exists(SuperCall call, Function constructor, ThisExpr thiz | + constructor = call.getEnclosingFunction() and + thiz.getBinder() = constructor and + DataFlow::valueNode(call.getCallee()).getPostUpdateNode().getASuccessor+() = + DataFlow::valueNode(thiz) and + location = call.getLocation() + ) + or + tag = "fieldReadContainerMismatch" and + value = "" and + exists(FieldDefinition field, Ssa2::ExprNode read, DataFlow::Node node | + read.getExpr() = field and + node = TSsaUseNode(read.getExpr()) and + node.getContainer() != field.getDeclaringClass().getConstructor().getBody() and + location = field.getLocation() + ) + ) + } +} + +import MakeTest diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/namespace.ts b/javascript/ql/test/library-tests/SharedSsaCompatibility/namespace.ts new file mode 100644 index 000000000000..c5f28576d9ff --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/namespace.ts @@ -0,0 +1,9 @@ +namespace SharedSsaNamespace { + let value: unknown; + if (check()) { + value = SOURCE("ts-namespace"); + } + if (value) { + SINK(value); // $ localRefinementFlow=ts-namespace noRefinementBypass=ts-namespace refinementFlow=ts-namespace refinementTaint=ts-namespace + } +} diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.expected b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js new file mode 100644 index 000000000000..0b57e9e2743d --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js @@ -0,0 +1,88 @@ +function ordinaryPhiNodes(condition, otherCondition) { + let value; + if (condition) { + value = "first"; + } else { + value = "second"; + } + if (otherCondition) { + CHECK(value); // $ uniquePhiDefinition phiNodeMetadata phiReachesCheck globalPhiReachesCheck + } else { + use(value); + } +} + +function refinedPhiNodes(value, condition) { + if (value) { + value = "safe"; + } + if (condition) { + CHECK(value); // $ uniquePhiDefinition phiNodeMetadata phiReachesCheck globalPhiReachesCheck + } else { + use(value); + } +} + +function nestedPhiNodes(firstCondition, secondCondition, thirdCondition) { + let value; + if (firstCondition) { + if (secondCondition) { + value = "first"; + } else { + value = "second"; + } + otherOperation(); + } else { + value = "third"; + } + if (thirdCondition) { + CHECK(value); // $ uniquePhiDefinition phiNodeMetadata phiReachesCheck globalPhiReachesCheck + } else { + use(value); + } +} + +function capturedPhiNodes(condition, otherCondition) { + let value; + if (condition) { + value = "first"; + } else { + value = "second"; + } + function capture() { + return value; + } + capture(); + if (otherCondition) { + CHECK(value); // $ uniquePhiDefinition phiNodeMetadata phiReachesCheck globalPhiReachesCheck + } else { + use(value); + } +} + +function sharedDefinitionApi(parameter) { + CHECK_NATIVE(parameter); // $ sharedDefinition + let uninitialized; + CHECK_NATIVE(uninitialized); // $ sharedDefinition + const { value } = { value: parameter }; + CHECK_NATIVE(value); // $ sharedDefinition + if (typeof value === "object") { + CHECK_NATIVE(value); // $ MISSING: sharedDefinition + } +} + +function capturedDefinitionApi() { + let value = 0; + function write() { + value = 1; + value = 2; + } + function* read() { + CHECK_NATIVE(value); // $ MISSING: sharedDefinition + yield; + CHECK_NATIVE(value); // $ MISSING: sharedDefinition + } + write(); + CHECK_NATIVE(value); // $ MISSING: sharedDefinition + return read; +} diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql new file mode 100644 index 000000000000..dfc888041705 --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql @@ -0,0 +1,91 @@ +import javascript +import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2 +import utils.test.InlineExpectationsTest + +module PhiConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.(DataFlow::SsaDefinitionNode).getSsaVariable().getDefinition() instanceof SsaPhiNode + } + + predicate isSink(DataFlow::Node sink) { + sink = any(DataFlow::InvokeNode check | check.getCalleeName() = "CHECK").getArgument(0) + } +} + +module PhiFlow = DataFlow::Global; + +module InlineTest implements TestSig { + string getARelevantTag() { + result = + [ + "uniquePhiDefinition", "phiNodeMetadata", "phiReachesCheck", "globalPhiReachesCheck", + "sharedDefinition" + ] + } + + predicate hasActualResult(Location location, string element, string tag, string value) { + element = "" and + value = "" and + location.getFile().getBaseName() = "nodes.js" and + ( + tag = "sharedDefinition" and + exists( + DataFlow::InvokeNode check, VarUse read, Ssa2::Definition definition, + Ssa2::SsaConfig::SourceVariable variable, BasicBlock bb, int index, BasicBlock defBlock, + int publicIndex, int nativeIndex + | + check.getCalleeName() = "CHECK_NATIVE" and + read = check.getArgument(0).asExpr() and + read = bb.getNode(index) and + variable.asLocalVariable() = read.getVariable() and + Ssa2::ssaDefReachesRead(variable, definition, bb, index) and + definition.definesAt(variable, defBlock, nativeIndex) and + read.getSsaVariable().getDefinition().definesAt(defBlock, publicIndex, read.getVariable()) and + ( + publicIndex = nativeIndex and nativeIndex >= 0 + or + publicIndex = 0 and nativeIndex = -1 + ) and + location = check.getLocation() + ) + or + exists(DataFlow::InvokeNode check, VarUse read, SsaPhiNode phi | + check.getCalleeName() = "CHECK" and + check.getArgument(0).asExpr() = read and + read.getSsaVariable().getDefinition() = phi and + location = check.getLocation() and + ( + tag = "uniquePhiDefinition" and + count(DataFlow::ssaDefinitionNode(phi)) = 1 + or + tag = "phiNodeMetadata" and + forall(DataFlow::Node node | node = DataFlow::ssaDefinitionNode(phi) | + exists(node.toString()) and + exists(node.getBasicBlock()) and + exists(node.getContainer()) and + exists(node.getLocation()) and + exists(node.getFile()) + ) + or + tag = "phiReachesCheck" and + forall(SsaPhiNode input | + input.getSourceVariable() = read.getVariable() and + input.getContainer() = check.getContainer() + | + DataFlow::ssaDefinitionNode(input).getASuccessor+() = check.getArgument(0) + ) + or + tag = "globalPhiReachesCheck" and + forall(SsaPhiNode input | + input.getSourceVariable() = read.getVariable() and + input.getContainer() = check.getContainer() + | + PhiFlow::flow(DataFlow::ssaDefinitionNode(input), check.getArgument(0)) + ) + ) + ) + ) + } +} + +import MakeTest diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.expected b/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js new file mode 100644 index 000000000000..97b733082133 --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js @@ -0,0 +1,493 @@ +function refinementBarrier() { + const refinementBarrierSource = SOURCE("refinement-barrier"); + if (!refinementBarrierSource) { + SINK(refinementBarrierSource); // $ barrier=refinement-barrier noRefinementFlow=refinement-barrier noRefinementTaint=refinement-barrier localRefinementFlow=refinement-barrier noRefinementBypass=refinement-barrier + } +} + +function propertyGuardDoesNotSanitizeBase(key) { + const object = SOURCE("guarded-property-base"); + if (!BARRIER(object[key])) return; + SINK(object[key]); // $ noRefinementFlow=guarded-property-base noRefinementTaint=guarded-property-base + SINK(object); // $ refinementFlow=guarded-property-base refinementTaint=guarded-property-base localRefinementFlow=guarded-property-base + key = OTHER_KEY(); + SINK(object[key]); // $ noRefinementFlow=guarded-property-base refinementTaint=guarded-property-base +} + +function phiReadInsideRefinement(condition) { + const phiReadSource = SOURCE("refined-phi-read"); + if (phiReadSource) { + if (condition) { + if (!BARRIER(phiReadSource)) return; + } else { + if (!BARRIER(phiReadSource)) return; + } + SINK(phiReadSource); // $ localRefinementFlow=refined-phi-read noRefinementBypass=refined-phi-read SPURIOUS: refinementFlow=refined-phi-read refinementTaint=refined-phi-read MISSING: noRefinementFlow=refined-phi-read noRefinementTaint=refined-phi-read + } +} + +function refinementFollowedByPhi(condition) { + let refinementPhiSource = SOURCE("refinement-phi"); + if (!refinementPhiSource) { + if (condition) { + refinementPhiSource = "safe"; + } + SINK(refinementPhiSource); // $ noRefinementFlow=refinement-phi noRefinementTaint=refinement-phi localRefinementFlow=refinement-phi noRefinementBypass=refinement-phi + } +} + +function equalityCompatibilityPhi() { + const value = SOURCE("equality-phi"); + if (value === "a" || value === "b") { + SINK(value); // $ refinementFlow=equality-phi noRefinementTaint=equality-phi localRefinementFlow=equality-phi noRefinementBypass=equality-phi + } +} + +function nestedCompatibilityPhi(condition) { + const value = SOURCE("nested-equality-phi"); + if (value === "a" || value === "b") { + if (condition) { + use(value); + } else { + use(value); + } + SINK(value); // $ refinementFlow=nested-equality-phi noRefinementTaint=nested-equality-phi localRefinementFlow=nested-equality-phi noRefinementBypass=nested-equality-phi + } +} + +function unguardedWriteAfterTruthyTest(value) { + if (value) { + value = SOURCE("unguarded-shared-phi"); + } + SINK(value); // $ refinementFlow=unguarded-shared-phi refinementTaint=unguarded-shared-phi localRefinementFlow=unguarded-shared-phi +} + +function unguardedWriteInsideFalseRefinement(value, condition) { + if (!value) { + if (condition) { + value = SOURCE("nested-shared-phi"); + } + SINK(value); // $ refinementFlow=nested-shared-phi refinementTaint=nested-shared-phi localRefinementFlow=nested-shared-phi + } +} + +function transitiveSharedPhis(value, condition) { + if (value) { + value = SOURCE("first-shared-phi"); + } + if (condition) { + value = SOURCE("second-shared-phi"); + } + SINK(value); // $ refinementFlow=first-shared-phi refinementTaint=first-shared-phi localRefinementFlow=first-shared-phi refinementFlow=second-shared-phi refinementTaint=second-shared-phi localRefinementFlow=second-shared-phi +} + +function phiReadAfterSharedPhi(value, condition) { + if (value) { + value = SOURCE("shared-phi-then-read"); + } + if (condition) { + use(value); + } else { + use(value); + } + SINK(value); // $ refinementFlow=shared-phi-then-read refinementTaint=shared-phi-then-read localRefinementFlow=shared-phi-then-read +} + +function filteredPhiInputWithReplacement(condition, otherCondition) { + let value = SOURCE("filtered-phi-input"); + if (!value) { + if (condition) { + value = SOURCE("replacement-phi-input"); + } + if (otherCondition) { + SINK(value); // $ noRefinementFlow=filtered-phi-input noRefinementTaint=filtered-phi-input localRefinementFlow=filtered-phi-input noRefinementBypass=filtered-phi-input refinementFlow=replacement-phi-input refinementTaint=replacement-phi-input localRefinementFlow=replacement-phi-input + } else { + SINK(value); // $ noRefinementFlow=filtered-phi-input noRefinementTaint=filtered-phi-input localRefinementFlow=filtered-phi-input noRefinementBypass=filtered-phi-input refinementFlow=replacement-phi-input refinementTaint=replacement-phi-input localRefinementFlow=replacement-phi-input + } + } + + function emptyRefinementBranches() { + const value = SOURCE("empty-refinement-branches"); + if (value) {} + SINK(value); // $ refinementFlow=empty-refinement-branches refinementTaint=empty-refinement-branches localRefinementFlow=empty-refinement-branches noRefinementBypass=empty-refinement-branches + } + + function nestedSingleReadPhis(firstCondition, secondCondition) { + let value; + if (firstCondition) { + if (secondCondition) { + value = SOURCE("nested-single-read-phis"); + } else { + value = "safe"; + } + otherOperation(); + } else { + value = "safe"; + } + SINK(value); // $ refinementFlow=nested-single-read-phis refinementTaint=nested-single-read-phis localRefinementFlow=nested-single-read-phis + } + + function nestedMultipleReadPhis(firstCondition, secondCondition, thirdCondition) { + let value; + if (firstCondition) { + if (secondCondition) { + value = SOURCE("nested-multiple-read-phis"); + } else { + value = "safe"; + } + otherOperation(); + } else { + value = "safe"; + } + if (thirdCondition) { + SINK(value); // $ refinementFlow=nested-multiple-read-phis refinementTaint=nested-multiple-read-phis localRefinementFlow=nested-multiple-read-phis + } else { + use(value); + } + } + + function refinementAfterGuardedJoin(condition) { + const value = SOURCE("refinement-after-guarded-join"); + if (value) { + if (condition) { + if (!BARRIER(value)) return; + } else { + if (!BARRIER(value)) return; + } + if (typeof value === "object") { + SINK(value); // $ localRefinementFlow=refinement-after-guarded-join noRefinementBypass=refinement-after-guarded-join SPURIOUS: refinementFlow=refinement-after-guarded-join refinementTaint=refinement-after-guarded-join MISSING: noRefinementFlow=refinement-after-guarded-join noRefinementTaint=refinement-after-guarded-join + } + } + } + + function conditionalReadInsideFalsyRefinement(condition) { + const value = SOURCE("conditional-read-in-refinement"); + if (!value) { + if (condition) { + use(value); + } + SINK(value); // $ barrier=conditional-read-in-refinement noRefinementTaint=conditional-read-in-refinement localRefinementFlow=conditional-read-in-refinement noRefinementFlow=conditional-read-in-refinement noRefinementBypass=conditional-read-in-refinement + } + } + + function independentPhiInputRefinements(condition, otherCondition) { + let value = SOURCE("independent-phi-inputs"); + if (condition) { + } else if (value) { + value = "safe"; + } + if (otherCondition) { + SINK(value); // $ localRefinementFlow=independent-phi-inputs refinementFlow=independent-phi-inputs refinementTaint=independent-phi-inputs + } else { + use(value); + } + } + + function occurrenceSpecificBarrier() { + const value = SOURCE("occurrence-barrier"); + BLOCKED_SINK(value); // $ noRefinementFlow=occurrence-barrier noRefinementTaint=occurrence-barrier localRefinementFlow=occurrence-barrier + SINK(value); // $ localRefinementFlow=occurrence-barrier refinementFlow=occurrence-barrier refinementTaint=occurrence-barrier + } + + function guardedCallResultDoesNotValidateArgument() { + const value = SOURCE("guarded-call-result"); + if (!BARRIER(transform(value))) return; + SINK(value); // $ localRefinementFlow=guarded-call-result refinementFlow=guarded-call-result refinementTaint=guarded-call-result + } + + function occurrenceSpecificBarriersBeforeJoin(condition) { + const value = SOURCE("occurrence-barriers-before-join"); + if (condition) { + BLOCKED_SINK(value); // $ noRefinementFlow=occurrence-barriers-before-join noRefinementTaint=occurrence-barriers-before-join localRefinementFlow=occurrence-barriers-before-join + } else { + BLOCKED_SINK(value); // $ noRefinementFlow=occurrence-barriers-before-join noRefinementTaint=occurrence-barriers-before-join localRefinementFlow=occurrence-barriers-before-join + } + SINK(value); // $ refinementFlow=occurrence-barriers-before-join refinementTaint=occurrence-barriers-before-join localRefinementFlow=occurrence-barriers-before-join + } + + function readOccurrenceSourceDoesNotContaminateVariable() { + const value = "safe"; + READ_SOURCE(value, "read-occurrence-source"); + SINK(value); // $ noRefinementFlow=read-occurrence-source noRefinementTaint=read-occurrence-source + } + + function indirectBarrierGuardWithReadBeforeJoin() { + let value = SOURCE("indirect-barrier-read-join"); + const ok = BARRIER(value); + if (ok) { + use(value); + } else { + value = "safe"; + } + SINK(value); // $ localRefinementFlow=indirect-barrier-read-join SPURIOUS: refinementFlow=indirect-barrier-read-join refinementTaint=indirect-barrier-read-join MISSING: noRefinementFlow=indirect-barrier-read-join noRefinementTaint=indirect-barrier-read-join + } + + function indirectBarrierGuardEmptyBranchBeforeJoin() { + let value = SOURCE("indirect-barrier-empty-join"); + const ok = BARRIER(value); + if (ok) { + } else { + value = "safe"; + } + SINK(value); // $ localRefinementFlow=indirect-barrier-empty-join SPURIOUS: refinementFlow=indirect-barrier-empty-join refinementTaint=indirect-barrier-empty-join MISSING: noRefinementFlow=indirect-barrier-empty-join noRefinementTaint=indirect-barrier-empty-join + } + + function indirectBarrierGuardAfterRefinementBeforeJoin() { + let value = SOURCE("indirect-barrier-after-refinement-join"); + const ok = BARRIER(value); + if (typeof value === "object") { + if (ok) { + } else { + value = "safe"; + } + SINK(value); // $ localRefinementFlow=indirect-barrier-after-refinement-join noRefinementBypass=indirect-barrier-after-refinement-join SPURIOUS: refinementFlow=indirect-barrier-after-refinement-join refinementTaint=indirect-barrier-after-refinement-join MISSING: noRefinementFlow=indirect-barrier-after-refinement-join noRefinementTaint=indirect-barrier-after-refinement-join + } + } + + function barrierGuardInsideWithStatement(scopeObject) { + let value = SOURCE("barrier-in-with"); + with (scopeObject) { + if (BARRIER(value)) { + use(value); + } else { + value = "safe"; + } + } + SINK(value); // $ localRefinementFlow=barrier-in-with SPURIOUS: refinementFlow=barrier-in-with refinementTaint=barrier-in-with MISSING: noRefinementFlow=barrier-in-with noRefinementTaint=barrier-in-with + } + + function mutatePreservedArgument(target, payload) { + target.property = payload; + } + + function selfAssignedArgument(value) { + mutatePreservedArgument(value, SOURCE("self-assigned-argument"), value = value); + SINK(value.property); // $ refinementFlow=self-assigned-argument refinementTaint=self-assigned-argument + } + + function wrappedSelfAssignedArgument(value) { + mutatePreservedArgument(value, (value = (use(), value), SOURCE("wrapped-self-assigned-argument"))); + SINK(value.property); // $ refinementFlow=wrapped-self-assigned-argument refinementTaint=wrapped-self-assigned-argument + } + + function selfAssignedStore(value) { + value.property = (value = value, SOURCE("self-assigned-store")); + SINK(value.property); // $ refinementFlow=self-assigned-store refinementTaint=self-assigned-store + } + + function copiedArgument(value) { + const alias = value; + mutatePreservedArgument(value, SOURCE("copied-argument"), value = alias); + SINK(value.property); // $ SPURIOUS: noRefinementFlow=copied-argument noRefinementTaint=copied-argument MISSING: refinementFlow=copied-argument refinementTaint=copied-argument + } + + function conditionalArgumentCopy(value, condition) { + mutatePreservedArgument(value, SOURCE("conditional-argument-copy"), value = condition ? value : {}); + SINK(value.property); // $ refinementFlow=conditional-argument-copy refinementTaint=conditional-argument-copy + } + + function identicalBranchArgumentCopy(value, condition) { + mutatePreservedArgument(value, SOURCE("identical-branch-copy"), value = condition ? value : value); + SINK(value.property); // $ refinementFlow=identical-branch-copy refinementTaint=identical-branch-copy + } + + function logicalDefaultArgument(value) { + mutatePreservedArgument(value, SOURCE("logical-default-argument"), value = value || {}); + SINK(value.property); // $ refinementFlow=logical-default-argument refinementTaint=logical-default-argument + } + + function nullishDefaultArgument(value) { + mutatePreservedArgument(value, SOURCE("nullish-default-argument"), value = value ?? {}); + SINK(value.property); // $ refinementFlow=nullish-default-argument refinementTaint=nullish-default-argument + } + + function logicalAndArgument(value, condition) { + mutatePreservedArgument(value, SOURCE("logical-and-argument"), value = condition && value); + SINK(value.property); // $ refinementFlow=logical-and-argument refinementTaint=logical-and-argument + } + + function nestedBranchArgument(value, condition) { + mutatePreservedArgument(value, SOURCE("nested-branch-argument"), value = condition ? (use(), value) : value ?? {}); + SINK(value.property); // $ refinementFlow=nested-branch-argument refinementTaint=nested-branch-argument + } + + function conditionalAliasArgument(value, condition) { + const alias = condition ? value : {}; + mutatePreservedArgument(value, SOURCE("conditional-alias-argument"), value = alias); + SINK(value.property); // $ SPURIOUS: noRefinementFlow=conditional-alias-argument noRefinementTaint=conditional-alias-argument MISSING: refinementFlow=conditional-alias-argument refinementTaint=conditional-alias-argument + } + + function conditionalStoreCopy(value, condition) { + value.property = (value = condition ? value : {}, SOURCE("conditional-store-copy")); + SINK(value.property); // $ refinementFlow=conditional-store-copy refinementTaint=conditional-store-copy + } + + function conditionalReplacement(value) { + mutatePreservedArgument(value, SOURCE("conditional-replacement"), value = value ? {} : {}); + SINK(value.property); // $ noRefinementFlow=conditional-replacement noRefinementTaint=conditional-replacement + } + + function discardedValueReplacement(value) { + mutatePreservedArgument(value, SOURCE("discarded-value-replacement"), value = (value, {})); + SINK(value.property); // $ noRefinementFlow=discarded-value-replacement noRefinementTaint=discarded-value-replacement + } + + function identityPreservedArgument(value) { + return value; + } + + function replacementPreservedArgument(unused) { + return {}; + } + + function arrayDestructuringArgumentCopy(value) { + mutatePreservedArgument(value, SOURCE("array-destructuring-copy"), [value] = [value]); + SINK(value.property); // $ refinementFlow=array-destructuring-copy refinementTaint=array-destructuring-copy + } + + function objectDestructuringArgumentCopy(value) { + mutatePreservedArgument(value, SOURCE("object-destructuring-copy"), { slot: value } = { slot: value }); + SINK(value.property); // $ refinementFlow=object-destructuring-copy refinementTaint=object-destructuring-copy + } + + function objectLiteralArgumentCopy(value) { + mutatePreservedArgument(value, SOURCE("object-literal-copy"), value = ({ slot: value }).slot); + SINK(value.property); // $ refinementFlow=object-literal-copy refinementTaint=object-literal-copy + } + + function arrayLiteralArgumentCopy(value) { + mutatePreservedArgument(value, SOURCE("array-literal-copy"), value = [value][0]); + SINK(value.property); // $ refinementFlow=array-literal-copy refinementTaint=array-literal-copy + } + + function identityCallArgumentCopy(value) { + mutatePreservedArgument(value, SOURCE("identity-call-copy"), value = identityPreservedArgument(value)); + SINK(value.property); // $ refinementFlow=identity-call-copy refinementTaint=identity-call-copy + } + + function identityCopyUpdateTiming(value) { + mutatePreservedArgument( + value, SOURCE("identity-copy-timing"), value = identityPreservedArgument(value), + SINK(value.property) // $ SPURIOUS: refinementFlow=identity-copy-timing refinementTaint=identity-copy-timing MISSING: noRefinementFlow=identity-copy-timing noRefinementTaint=identity-copy-timing + ); + SINK(value.property); // $ refinementFlow=identity-copy-timing refinementTaint=identity-copy-timing + } + + function identityCallReplacement(value) { + mutatePreservedArgument(value, SOURCE("identity-call-replacement"), value = replacementPreservedArgument(value)); + SINK(value.property); // $ noRefinementFlow=identity-call-replacement noRefinementTaint=identity-call-replacement + } + + function destructuringArgumentReplacement(value) { + mutatePreservedArgument(value, SOURCE("destructuring-argument-replacement"), [value] = [{}]); + SINK(value.property); // $ noRefinementFlow=destructuring-argument-replacement noRefinementTaint=destructuring-argument-replacement + } + + function objectLiteralArgumentReplacement(value) { + mutatePreservedArgument(value, SOURCE("object-literal-replacement"), value = ({ slot: {} }).slot); + SINK(value.property); // $ noRefinementFlow=object-literal-replacement noRefinementTaint=object-literal-replacement + } + + function composedModeledCopy(value) { + mutatePreservedArgument( + value, SOURCE("composed-modeled-copy"), [value] = [identityPreservedArgument(value)] + ); + SINK(value.property); // $ refinementFlow=composed-modeled-copy refinementTaint=composed-modeled-copy + } + + function wrappedReplacementArgument(value) { + function wrap(input) { + return { nested: input }; + } + mutatePreservedArgument(value, SOURCE("wrapped-replacement-argument"), value = wrap(value)); + SINK(value.property); // $ noRefinementFlow=wrapped-replacement-argument noRefinementTaint=wrapped-replacement-argument + } + + function truthyReplacement(value) { + mutatePreservedArgument(value, SOURCE("truthy-replacement"), value = {} || value); + SINK(value.property); // $ SPURIOUS: refinementFlow=truthy-replacement refinementTaint=truthy-replacement + } + + function nonNullishReplacement(value) { + mutatePreservedArgument(value, SOURCE("non-nullish-replacement"), value = {} ?? value); + SINK(value.property); // $ SPURIOUS: refinementFlow=non-nullish-replacement refinementTaint=non-nullish-replacement + } + + // These copy-model false positives also occur with the baseline data-flow library. + function clonedArgument(value) { + mutatePreservedArgument(value, SOURCE("cloned-argument"), value = Object.assign({}, value)); + SINK(value.property); // $ SPURIOUS: refinementFlow=cloned-argument refinementTaint=cloned-argument + } + + function libraryClonedArgument(value) { + const clone = require("clone"); + mutatePreservedArgument(value, SOURCE("library-cloned-argument"), value = clone(value)); + SINK(value.property); // $ SPURIOUS: refinementFlow=library-cloned-argument refinementTaint=library-cloned-argument + } + + function mixedReplacementArgument(value, condition) { + mutatePreservedArgument( + value, SOURCE("mixed-replacement-argument"), + value = condition ? ({} || value) : replacementPreservedArgument(value) + ); + SINK(value.property); // $ SPURIOUS: refinementFlow=mixed-replacement-argument refinementTaint=mixed-replacement-argument + } + + function mixedNullishReplacementArgument(value, condition) { + mutatePreservedArgument( + value, SOURCE("mixed-nullish-replacement-argument"), + value = condition ? ({} ?? value) : replacementPreservedArgument(value) + ); + SINK(value.property); // $ SPURIOUS: refinementFlow=mixed-nullish-replacement-argument refinementTaint=mixed-nullish-replacement-argument + } + + function assignOriginalArgument(value) { + mutatePreservedArgument(value, SOURCE("assign-original-argument"), value = Object.assign(value, {})); + SINK(value.property); // $ refinementFlow=assign-original-argument refinementTaint=assign-original-argument + } + + function constantConditionReplacement(value) { + mutatePreservedArgument(value, SOURCE("constant-condition-replacement"), value = true ? {} : value); + SINK(value.property); // $ noRefinementFlow=constant-condition-replacement noRefinementTaint=constant-condition-replacement + } + + function falsyReplacement(value) { + mutatePreservedArgument(value, SOURCE("falsy-replacement"), value = false && value); + SINK(value.property); // $ noRefinementFlow=falsy-replacement noRefinementTaint=falsy-replacement + } + + function replacedArgument(value) { + mutatePreservedArgument(value, SOURCE("replaced-argument"), value = {}); + SINK(value.property); // $ noRefinementFlow=replaced-argument noRefinementTaint=replaced-argument + } + + function replacedStore(value) { + value.property = (value = {}, SOURCE("replaced-store")); + SINK(value.property); // $ noRefinementFlow=replaced-store noRefinementTaint=replaced-store + } + + function overwrittenCopiedArgument(value) { + let alias = value; + alias = {}; + mutatePreservedArgument(value, SOURCE("overwritten-copied-argument"), value = alias); + SINK(value.property); // $ noRefinementFlow=overwritten-copied-argument noRefinementTaint=overwritten-copied-argument + } + + class SharedSsaThisTests { + guardedThisMethod(condition) { + if (condition) { + if (!BARRIER(this)) return; + } else { + if (!BARRIER(this)) return; + } + SINK(this); // $ localRefinementFlow=this-guard SPURIOUS: refinementFlow=this-guard refinementTaint=this-guard MISSING: noRefinementFlow=this-guard noRefinementTaint=this-guard + } + + occurrenceBarrierThisMethod() { + this.property = SOURCE("this-occurrence-barrier"); + BLOCKED_SINK(this.property); // $ noRefinementFlow=this-occurrence-barrier noRefinementTaint=this-occurrence-barrier + BLOCKED_SINK(this); // $ noRefinementFlow=this-occurrence-barrier noRefinementTaint=this-occurrence-barrier + SINK(this.property); // $ refinementFlow=this-occurrence-barrier refinementTaint=this-occurrence-barrier + } + } +} diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.ql new file mode 100644 index 000000000000..7ffe1838f2e3 --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.ql @@ -0,0 +1,119 @@ +import javascript +import utils.test.InlineExpectationsTest + +module RefinementConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.(DataFlow::InvokeNode).getCalleeName() = "SOURCE" + or + source = any(DataFlow::InvokeNode call | call.getCalleeName() = "READ_SOURCE").getArgument(0) + or + exists(Function method | + method = any(MethodDeclaration decl | decl.getName() = "guardedThisMethod").getBody() and + source = DataFlow::thisNode(method) + ) + } + + predicate isSink(DataFlow::Node sink) { + exists(DataFlow::InvokeNode call | + call.getCalleeName() = ["SINK", "BLOCKED_SINK"] and + sink = call.getArgument(0) + ) + } + + predicate isBarrier(DataFlow::Node node) { + node instanceof DataFlow::VarAccessBarrier + or + node = DataFlow::MakeBarrierGuard::getABarrierNode() + or + node = any(DataFlow::InvokeNode call | call.getCalleeName() = "BLOCKED_SINK").getArgument(0) + } +} + +module RefinementFlow = DataFlow::Global; + +module RefinementTaint = TaintTracking::Global; + +class SimpleBarrierGuard extends DataFlow::InvokeNode { + SimpleBarrierGuard() { this.getCalleeName() = "BARRIER" } + + predicate blocksExpr(boolean outcome, Expr expr) { + outcome = true and + expr = this.getArgument(0).asExpr() + } +} + +private predicate localStepWithoutRefinement(DataFlow::Node pred, DataFlow::Node succ) { + DataFlow::localFlowStep(pred, succ) and + not succ.(DataFlow::SsaDefinitionNode).getSsaVariable().getDefinition() instanceof + SsaRefinementNode +} + +module InlineTest implements TestSig { + string getARelevantTag() { + result = + [ + "barrier", "refinementFlow", "noRefinementFlow", "refinementTaint", "noRefinementTaint", + "localRefinementFlow", "noRefinementBypass" + ] + } + + predicate hasActualResult(Location location, string element, string tag, string value) { + element = "" and + location.getFile().getBaseName() = ["refinement.js", "namespace.ts"] and + exists(DataFlow::Node source, DataFlow::InvokeNode sink, Expr sinkArgument, boolean allowLocal | + ( + exists(DataFlow::InvokeNode sourceCall | + sourceCall.getCalleeName() = "SOURCE" and + source = sourceCall and + value = sourceCall.getArgument(0).getStringValue() and + allowLocal = true + or + sourceCall.getCalleeName() = "READ_SOURCE" and + source = sourceCall.getArgument(0) and + value = sourceCall.getArgument(1).getStringValue() and + allowLocal = false + ) + or + exists(MethodDeclaration decl | + source = DataFlow::thisNode(decl.getBody()) and + allowLocal = true and + decl.getName() = "guardedThisMethod" and + value = "this-guard" + ) + ) and + sink.getCalleeName() = ["SINK", "BLOCKED_SINK"] and + source.getContainer() = sink.getContainer() and + sink.getArgument(0) = DataFlow::valueNode(sinkArgument) and + ( + sinkArgument instanceof VarRef or + sinkArgument instanceof ThisExpr or + sinkArgument instanceof PropAccess + ) and + location = sink.getLocation() and + ( + tag = "refinementFlow" and RefinementFlow::flow(source, sink.getArgument(0)) + or + tag = "noRefinementFlow" and not RefinementFlow::flow(source, sink.getArgument(0)) + or + tag = "refinementTaint" and RefinementTaint::flow(source, sink.getArgument(0)) + or + tag = "noRefinementTaint" and not RefinementTaint::flow(source, sink.getArgument(0)) + or + tag = "localRefinementFlow" and + allowLocal = true and + source.getASuccessor*() = sink.getArgument(0) + or + tag = "noRefinementBypass" and + allowLocal = true and + source.getASuccessor*() = sink.getArgument(0) and + not localStepWithoutRefinement*(source, sink.getArgument(0)) + or + tag = "barrier" and + DataFlow::ssaDefinitionNode(sinkArgument.(VarUse).getSsaVariable().getDefinition()) + instanceof DataFlow::VarAccessBarrier + ) + ) + } +} + +import MakeTest diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/test.expected b/javascript/ql/test/library-tests/SharedSsaCompatibility/test.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/test.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/test.ql new file mode 100644 index 000000000000..10cde765bddd --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/test.ql @@ -0,0 +1,44 @@ +import javascript +import utils.test.InlineExpectationsTest + +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + exists(SsaPhiNode phi | + phi.getSourceVariable().getName() = "compatibilityPhiSource" and + source = DataFlow::ssaDefinitionNode(phi) + ) + } + + predicate isSink(DataFlow::Node sink) { + exists(DataFlow::InvokeNode call | + call.getCalleeName() = "SINK" and + sink = call.getArgument(0) + ) + } +} + +module TestFlow = DataFlow::Global; + +module InlineTest implements TestSig { + string getARelevantTag() { result = ["source", "flow"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = ["source", "flow"] and + element = "" and + value = "compatibility-phi" and + exists(DataFlow::Node source, DataFlow::InvokeNode sink, VarRef sinkArgument | + TestConfig::isSource(source) and + sink.getCalleeName() = "SINK" and + sink.getArgument(0) = DataFlow::valueNode(sinkArgument) and + sinkArgument.getVariable().getName() = "compatibilityPhiSource" and + location = sink.getLocation() and + ( + tag = "source" + or + tag = "flow" and TestFlow::flow(source, sink.getArgument(0)) + ) + ) + } +} + +import MakeTest diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/tst.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/tst.js new file mode 100644 index 000000000000..cc0b1c93f7a1 --- /dev/null +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/tst.js @@ -0,0 +1,10 @@ +function compatibilityPhi(start, end) { + let compatibilityPhiSource; + for ( + compatibilityPhiSource = start; + compatibilityPhiSource < end; + compatibilityPhiSource++ + ) { + } + SINK(compatibilityPhiSource); // $ source=compatibility-phi flow=compatibility-phi +} diff --git a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected index 85d629191c5a..5da2f2819639 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected @@ -3,19 +3,22 @@ | second-order.js:9:29:9:34 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:9:29:9:34 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value | | second-order.js:11:33:11:38 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:11:33:11:38 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value | | second-order.js:15:19:15:24 | myArgs | second-order.js:13:18:13:31 | req.query.args | second-order.js:15:19:15:24 | myArgs | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:13:18:13:31 | req.query.args | a user-provided value | -| second-order.js:26:35:26:40 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:26:35:26:40 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value | -| second-order.js:29:19:29:32 | req.query.args | second-order.js:29:19:29:32 | req.query.args | second-order.js:29:19:29:32 | req.query.args | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:29:19:29:32 | req.query.args | a user-provided value | -| second-order.js:40:28:40:43 | req.query.remote | second-order.js:40:28:40:43 | req.query.remote | second-order.js:40:28:40:43 | req.query.remote | Command line argument that depends on $@ can execute an arbitrary command if --config=alias.= is used with hg. | second-order.js:40:28:40:43 | req.query.remote | a user-provided value | -| second-order.js:42:31:42:46 | req.query.remote | second-order.js:42:31:42:46 | req.query.remote | second-order.js:42:31:42:46 | req.query.remote | Command line argument that depends on $@ can execute an arbitrary command if --config=alias.= is used with hg. | second-order.js:42:31:42:46 | req.query.remote | a user-provided value | -| second-order.js:44:18:44:31 | req.query.args | second-order.js:44:18:44:31 | req.query.args | second-order.js:44:18:44:31 | req.query.args | Command line argument that depends on $@ can execute an arbitrary command if --config=alias.= is used with hg. | second-order.js:44:18:44:31 | req.query.args | a user-provided value | +| second-order.js:23:33:23:38 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:23:33:23:38 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value | +| second-order.js:29:35:29:49 | uncheckedRemote | second-order.js:25:27:25:51 | req.que ... dRemote | second-order.js:29:35:29:49 | uncheckedRemote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:25:27:25:51 | req.que ... dRemote | a user-provided value | +| second-order.js:32:19:32:32 | req.query.args | second-order.js:32:19:32:32 | req.query.args | second-order.js:32:19:32:32 | req.query.args | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:32:19:32:32 | req.query.args | a user-provided value | +| second-order.js:43:28:43:43 | req.query.remote | second-order.js:43:28:43:43 | req.query.remote | second-order.js:43:28:43:43 | req.query.remote | Command line argument that depends on $@ can execute an arbitrary command if --config=alias.= is used with hg. | second-order.js:43:28:43:43 | req.query.remote | a user-provided value | +| second-order.js:45:31:45:46 | req.query.remote | second-order.js:45:31:45:46 | req.query.remote | second-order.js:45:31:45:46 | req.query.remote | Command line argument that depends on $@ can execute an arbitrary command if --config=alias.= is used with hg. | second-order.js:45:31:45:46 | req.query.remote | a user-provided value | +| second-order.js:47:18:47:31 | req.query.args | second-order.js:47:18:47:31 | req.query.args | second-order.js:47:18:47:31 | req.query.args | Command line argument that depends on $@ can execute an arbitrary command if --config=alias.= is used with hg. | second-order.js:47:18:47:31 | req.query.args | a user-provided value | edges | second-order.js:6:9:6:14 | remote | second-order.js:7:33:7:38 | remote | provenance | | | second-order.js:6:9:6:14 | remote | second-order.js:9:29:9:34 | remote | provenance | | | second-order.js:6:9:6:14 | remote | second-order.js:11:33:11:38 | remote | provenance | | -| second-order.js:6:9:6:14 | remote | second-order.js:26:35:26:40 | remote | provenance | | +| second-order.js:6:9:6:14 | remote | second-order.js:23:33:23:38 | remote | provenance | | | second-order.js:6:18:6:33 | req.query.remote | second-order.js:6:9:6:14 | remote | provenance | | | second-order.js:13:9:13:14 | myArgs | second-order.js:15:19:15:24 | myArgs | provenance | | | second-order.js:13:18:13:31 | req.query.args | second-order.js:13:9:13:14 | myArgs | provenance | | +| second-order.js:25:9:25:23 | uncheckedRemote | second-order.js:29:35:29:49 | uncheckedRemote | provenance | | +| second-order.js:25:27:25:51 | req.que ... dRemote | second-order.js:25:9:25:23 | uncheckedRemote | provenance | | nodes | second-order.js:6:9:6:14 | remote | semmle.label | remote | | second-order.js:6:18:6:33 | req.query.remote | semmle.label | req.query.remote | @@ -25,9 +28,12 @@ nodes | second-order.js:13:9:13:14 | myArgs | semmle.label | myArgs | | second-order.js:13:18:13:31 | req.query.args | semmle.label | req.query.args | | second-order.js:15:19:15:24 | myArgs | semmle.label | myArgs | -| second-order.js:26:35:26:40 | remote | semmle.label | remote | -| second-order.js:29:19:29:32 | req.query.args | semmle.label | req.query.args | -| second-order.js:40:28:40:43 | req.query.remote | semmle.label | req.query.remote | -| second-order.js:42:31:42:46 | req.query.remote | semmle.label | req.query.remote | -| second-order.js:44:18:44:31 | req.query.args | semmle.label | req.query.args | +| second-order.js:23:33:23:38 | remote | semmle.label | remote | +| second-order.js:25:9:25:23 | uncheckedRemote | semmle.label | uncheckedRemote | +| second-order.js:25:27:25:51 | req.que ... dRemote | semmle.label | req.que ... dRemote | +| second-order.js:29:35:29:49 | uncheckedRemote | semmle.label | uncheckedRemote | +| second-order.js:32:19:32:32 | req.query.args | semmle.label | req.query.args | +| second-order.js:43:28:43:43 | req.query.remote | semmle.label | req.query.remote | +| second-order.js:45:31:45:46 | req.query.remote | semmle.label | req.query.remote | +| second-order.js:47:18:47:31 | req.query.args | semmle.label | req.query.args | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js index b49d6b2bd73b..946706c89bcc 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js @@ -20,10 +20,13 @@ app.get("/", (req, res) => { execFile("git", ["ls-remote", remote, "HEAD"]); // OK - it's not an option } - if (remote.startsWith("git@")) { - execFile("git", ["ls-remote", remote, "HEAD"]); // OK - it's a git URL + execFile("git", ["ls-remote", remote, "HEAD"]); // $ SPURIOUS: Alert - both outcomes of the earlier check are modeled as safe. + + const uncheckedRemote = req.query.uncheckedRemote; // $ Source + if (uncheckedRemote.startsWith("git@")) { + execFile("git", ["ls-remote", uncheckedRemote, "HEAD"]); // OK - it's a git URL } else { - execFile("git", ["ls-remote", remote, "HEAD"]); // $ Alert - unknown starting string + execFile("git", ["ls-remote", uncheckedRemote, "HEAD"]); // $ Alert - unknown starting string } execFile("git", req.query.args); // $ Alert - unknown args From 6d15e519777c61ea63153ca7e85d1108ab11ab9e Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 29 Oct 2026 13:36:27 +0000 Subject: [PATCH 2/3] SSA: Support retained phi definitions and refinement barriers Add opt-in phi-definition retention for JavaScript's public SSA node API. Follow value-preserving uncertain definitions when determining guarded phi inputs. Keep phi retention disabled by default for existing clients. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- shared/ssa/codeql/ssa/Ssa.qll | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/shared/ssa/codeql/ssa/Ssa.qll b/shared/ssa/codeql/ssa/Ssa.qll index 6cc685f8ef8b..a7fcb3f6c075 100644 --- a/shared/ssa/codeql/ssa/Ssa.qll +++ b/shared/ssa/codeql/ssa/Ssa.qll @@ -1483,6 +1483,15 @@ module Make< */ default predicate includeWriteDefsInFlowStep() { any() } + /** + * Holds if phi definitions should always have a data flow node, even when + * they have a unique next reference. This is useful for language-specific + * APIs that expose a node for each SSA definition. + * + * Phi reads may still be skipped. + */ + default predicate includePhiDefsInFlowStep() { none() } + /** * Holds if barrier guards should be supported on input edges to phi * nodes. Disable this only if barrier guards are not going to be used. @@ -1540,9 +1549,20 @@ module Make< ) } + private Definition getAValuePreservingInputDef(Definition def) { + result = def + or + exists(Definition inp | + DfInput::allowFlowIntoUncertainDef(def) and + not DfInput::ssaDefHasSource(def) and + uncertainWriteDefinitionInput(def, inp) and + result = getAValuePreservingInputDef(inp) + ) + } + pragma[nomagic] private predicate phiInputHasRead(SsaPhiExt phi, BasicBlock input) { - exists(DfInput::getARead(getAPhiInputDef(phi, input))) + exists(DfInput::getARead(getAValuePreservingInputDef(getAPhiInputDef(phi, input)))) } /** Holds if `bb` is the target end of a branch edge of a guard and the guard controls `bb`. */ @@ -1667,6 +1687,7 @@ module Make< * flow edges. */ private predicate phiHasUniqNextNode(SsaPhiExt phi) { + not (phi instanceof PhiNode and DfInput::includePhiDefsInFlowStep()) and not relevantBackEdge(phi, _) and exists(int nextPhiInput, int nextPhi, int nextRef | 1 = nextPhiInput + nextPhi + nextRef and @@ -2119,7 +2140,7 @@ module Make< private predicate guardChecksSsaDef( DfInput::Guard g, Definition def, DfInput::GuardValue val, State state ) { - guardChecks(g, DfInput::getARead(def), val, state) + guardChecks(g, DfInput::getARead(getAValuePreservingInputDef(def)), val, state) } private module Barrier = BarrierGuardDefWithState; From fda35fca220c8c723faeddcab1a592c07dce20c2 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 29 Oct 2026 13:38:45 +0000 Subject: [PATCH 3/3] JS: Complete migration to shared SSA Use shared SSA for definitions, refinements, captures, and local/global data flow. Remove JavaScript's separate liveness, phi insertion, and reaching-definition computation while preserving its public SSA APIs as shared-backed adapters. Keep global continuing-value reads distinct from expression occurrences, preserve captured-variable and legacy Configuration guard behavior, and restrict reflective with-read shortcuts to type inference. Propagate post-updates after operation completion and preserve updates across value-preserving reassignments using the existing modeled may-value flow. Update test expectations and the change note. Keep known baseline clone and short-circuit false positives marked SPURIOUS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../lib/change-notes/2026-10-29-shared-ssa.md | 4 + javascript/ql/lib/semmle/javascript/SSA.qll | 681 +++--------------- .../javascript/dataflow/Configuration.qll | 7 +- .../semmle/javascript/dataflow/DataFlow.qll | 276 +++++-- .../javascript/dataflow/TypeInference.qll | 6 +- .../dataflow/internal/BarrierGuards.qll | 16 +- .../dataflow/internal/DataFlowNode.qll | 25 +- .../dataflow/internal/DataFlowPrivate.qll | 146 ++-- .../dataflow/internal/sharedlib/Ssa.qll | 326 ++++++++- javascript/ql/src/NodeJS/InvalidExport.ql | 2 + .../BarrierGuardPhiInputs/tst.js | 6 +- .../CallGraphs/FullTest/tests.expected | 2 + .../library-tests/DataFlow/tests.expected | 85 ++- .../GlobalAccessPaths.expected | 1 + .../SharedSsaCompatibility/captured.js | 4 +- .../invariants.expected | 481 ------------- .../SharedSsaCompatibility/invariants.ql | 17 +- .../SharedSsaCompatibility/local.js | 52 +- .../SharedSsaCompatibility/local.ql | 2 +- .../SharedSsaCompatibility/nodes.js | 8 +- .../SharedSsaCompatibility/nodes.ql | 11 +- .../SharedSsaCompatibility/refinement.js | 20 +- .../TaintTracking/BasicTaintTracking.expected | 4 +- .../TaintTracking/DataFlowTracking.expected | 4 +- .../library-tests/TaintTracking/booleanOps.js | 2 +- .../TaintTracking/sanitizer-guards.js | 2 +- .../AngularJS/scopes/ScopeAccess.expected | 8 + .../frameworks/Electron/tests.expected | 2 + .../frameworks/Express/tests.expected | 249 +++++++ .../frameworks/NodeJSLib/tests.expected | 40 + .../frameworks/ReactJS/tests.expected | 37 + .../frameworks/fastify/tests.expected | 11 + .../frameworks/hapi/tests.expected | 40 + .../frameworks/koa/tests.expected | 68 ++ .../frameworks/restify/tests.expected | 28 + .../CWE-022/TaintedPath/TaintedPath.expected | 3 - .../CWE-022/TaintedPath/normalizedPaths.js | 2 +- .../SecondOrderCommandInjection.expected | 3 - .../second-order.js | 2 +- .../UnsafeShellCommandConstruction.expected | 14 - .../UnsafeShellCommandConstruction/lib/lib.js | 2 +- .../Security/CWE-079/DomBasedXss/Xss.expected | 3 - .../XssWithAdditionalSources.expected | 3 - .../CWE-089/untyped/SqlInjection.expected | 16 - .../Security/CWE-089/untyped/koarouter.js | 4 +- .../PrototypePollutingFunction.expected | 21 - .../PrototypePollutingFunction/tests.js | 4 +- 47 files changed, 1413 insertions(+), 1337 deletions(-) create mode 100644 javascript/ql/lib/change-notes/2026-10-29-shared-ssa.md diff --git a/javascript/ql/lib/change-notes/2026-10-29-shared-ssa.md b/javascript/ql/lib/change-notes/2026-10-29-shared-ssa.md new file mode 100644 index 000000000000..fbb9181d3fd3 --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-10-29-shared-ssa.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* JavaScript and TypeScript data flow now use the shared SSA implementation, including refinements and conservative captured-variable definitions. The existing public SSA APIs remain available as shared-backed adapters; the separate JavaScript SSA computation has been removed. This improves barrier-guard handling at control-flow joins, reducing false positives when guarded and overwritten values merge, and improves the ordering of post-update flow around calls and assignments. diff --git a/javascript/ql/lib/semmle/javascript/SSA.qll b/javascript/ql/lib/semmle/javascript/SSA.qll index 04d08c2343f6..06c79deedaa7 100644 --- a/javascript/ql/lib/semmle/javascript/SSA.qll +++ b/javascript/ql/lib/semmle/javascript/SSA.qll @@ -1,410 +1,42 @@ /** - * Provides classes for working with static single assignment form (SSA). + * Provides the JavaScript-facing static single assignment (SSA) API. * - * We compute SSA form based on the intra-procedural CFG, without - * any call graph information. This means that we have to make worst-case - * assumptions about the possible effects of function calls and `yield`: + * Definitions, liveness, phi insertion, and reaching definitions are computed + * by the shared SSA library. These classes retain the JavaScript API and + * presentation of explicit writes, implicit initializations, captures, and + * value-preserving refinements. * - * - For a variable `x` declared in a function `f`, if `x` has assignments - * in a function other than `f`, then any function call and `yield` - * expression is assumed to write `x`. - * - If `x` is not written outside `f`, then function calls can never - * affect `x`, while `yield` expressions in functions other than `f` - * still may affect it. - * - * This is modeled as follows. - * - * Within each function `g` that accesses a variable `x` declared in an - * enclosing function `f`, we introduce a pseudo-assignment to `x` called - * a _capture_ of `x` at the beginning of `g` that (conceptually) captures - * the current value of `x`. - * - * Additionally, we introduce _re-captures_ for `x` in the following - * places: - * - * - At any function call and `yield`, if `x` is assigned outside `f`. - * - At any `yield` outside `f`, if `x` is not assigned outside `f`. - * - * Re-captures are introduced only where needed, that is, where there - * is a live use of `x` after the re-capture. - * - * To see why re-captures need to be placed at `yield` expressions, - * consider the following function: - * - * ``` - * function k() { - * var x = 0; - * - * function* iter() { - * console.log(x); - * yield; - * console.log(x); - * } - * - * var gen = iter(); - * gen.next(); - * ++x; - * gen.next(); - * } - * ``` - * - * Here, `iter` has a capture for `x` at its beginning, and a re-capture - * at the `yield` to reflect the fact that `x` is incremented between the - * two `console.log` calls. - * - * In the above example, `x` is only assigned inside its declaring function - * `k`, so function calls and `yield` expressions inside `k` cannot affect it. - * - * Consider another example: - * - * ``` - * function* k() { - * var x = 0; - * console.log(x); - * yield () => ++x; - * console.log(x); - * } - * var gen = k(); - * gen.next().value(); - * gen.next(); - * ``` - * - * Here, `x` is assigned outside its declaring function `k`, so the `yield` - * expression in `k` induces a re-capture of `x` to reflect the fact that `x` - * is incremented between the two `console.log` calls. + * Captured variables are conservatively recaptured at entry to a capturing + * function, at yields, and at calls that may observe non-local assignments. + * The global data-flow library separately uses shared variable-capture flow + * where more precise call-graph information is available. */ overlay[local?] module; import javascript private import semmle.javascript.dataflow.Refinements -private import semmle.javascript.internal.CachedStages +private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Shared -/** - * A variable that can be SSA converted, that is, a local variable. - */ +/** A variable that can be SSA converted, that is, a local variable. */ class SsaSourceVariable extends LocalVariable { } -cached -private module Internal { - /** - * A data type representing SSA definitions. - * - * We distinguish five kinds of SSA definitions: - * - * 1. Explicit definitions wrapping a `VarDef` node in the CFG. - * 2. Implicit initializations of locals (including `arguments`) at - * the start of a function, which do not correspond directly to - * CFG nodes. - * 3. Pseudo-definitions for captured variables at the beginning of - * the capturing function as well as after `yield` expressions - * and calls. - * 4. Phi nodes. - * 5. Refinement nodes at points in the CFG where additional information - * about a variable becomes available, which may constrain the set of - * its potential values. - * - * SSA definitions are only introduced where necessary. In particular, - * unreachable code has no SSA definitions associated with it, and neither - * have dead assignments (that is, assignments whose value is never read). - */ - cached - newtype TSsaDefinition = - TExplicitDef(ReachableBasicBlock bb, int i, VarDef d, SsaSourceVariable v, VarRef lhs) { - bb.defAt(i, v, d, lhs) and - ( - liveAfterDef(bb, i, v) or - v.isCaptured() - ) - } or - TImplicitInit(EntryBasicBlock bb, SsaSourceVariable v) { - bb.getContainer() = v.getDeclaringContainer().getFunctionBoundary() and - (liveAtEntry(bb, v) or v.isCaptured()) - } or - TCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - mayCapture(bb, i, v) and liveAfterDef(bb, i, v) - } or - TPhi(ReachableJoinBlock bb, SsaSourceVariable v) { - liveAtEntry(bb, v) and - inDefDominanceFrontier(bb, v) - } or - TRefinement(ReachableBasicBlock bb, int i, GuardControlFlowNode guard, SsaSourceVariable v) { - bb.getNode(i) = guard and - guard.getTest().(Refinement).getRefinedVar() = v and - liveAtEntry(bb, v) - } - - /** - * Holds if `bb` is in the dominance frontier of a block containing a definition of `v`. - */ - pragma[noinline] - private predicate inDefDominanceFrontier(ReachableJoinBlock bb, SsaSourceVariable v) { - exists(ReachableBasicBlock defbb, SsaDefinition def | - def.definesAt(defbb, _, v) and - bb.inDominanceFrontierOf(defbb) - ) - } - - /** - * Holds if `v` is a captured variable which is declared in `declContainer` and read in - * `useContainer`. - */ - private predicate readsCapturedVar( - StmtContainer useContainer, SsaSourceVariable v, StmtContainer declContainer - ) { - declContainer = v.getDeclaringContainer() and - useContainer = any(VarUse u | u.getVariable() = v).getContainer() and - v.isCaptured() - } - - /** - * Holds if the `i`th node of `bb` in container `sc` is entry node `nd`. - */ - private predicate entryNode( - StmtContainer sc, ReachableBasicBlock bb, int i, ControlFlowEntryNode nd - ) { - sc = bb.getContainer() and bb.getNode(i) = nd - } - - /** - * Holds if the `i`th node of `bb` in container `sc` is yield expression `nd`. - */ - private predicate yieldNode(StmtContainer sc, ReachableBasicBlock bb, int i, YieldExpr nd) { - sc = bb.getContainer() and bb.getNode(i) = nd - } - - /** - * Holds if the `i`th node of `bb` in container `sc` is invocation expression `nd`. - */ - private predicate invokeNode(StmtContainer sc, ReachableBasicBlock bb, int i, InvokeExpr nd) { - sc = bb.getContainer() and bb.getNode(i) = nd - } - - /** - * Holds if the `i`th node of basic block `bb` may induce a pseudo-definition for - * modeling updates to captured variable `v`. Whether the definition is actually - * introduced depends on whether `v` is live at this point in the program. - */ - private predicate mayCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - exists(ControlFlowNode nd, StmtContainer capturingContainer, StmtContainer declContainer | - // capture initial value of variable declared in enclosing scope - readsCapturedVar(capturingContainer, v, declContainer) and - capturingContainer != declContainer and - entryNode(capturingContainer, bb, i, nd) - or - // re-capture value of variable after `yield` if it is declared in enclosing scope - // or assigned non-locally - readsCapturedVar(capturingContainer, v, declContainer) and - (capturingContainer != declContainer or assignedThroughClosure(v)) and - yieldNode(capturingContainer, bb, i, nd) - or - // re-capture value of variable after a call if it is assigned non-locally - readsCapturedVar(capturingContainer, v, declContainer) and - assignedThroughClosure(v) and - invokeNode(capturingContainer, bb, i, nd) - ) - } - - /** - * A classification of variable references into reads and writes. - */ - cached - newtype RefKind = - Read() or - Write() - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, either a read - * (when `tp` is `Read()`) or a direct or indirect write (when `tp` is `Write()`). - */ - private predicate ref(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind tp) { - bb.useAt(i, v, _) and tp = Read() - or - (mayCapture(bb, i, v) or bb.defAt(i, v, _)) and - tp = Write() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic block `bb`, - * which has the given reference kind `tp`. - */ - private int refRank(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind tp) { - i = rank[result](int j | ref(bb, j, v, _)) and - ref(bb, i, v, tp) - } - - /** - * Gets the maximum rank among all references to `v` in basic block `bb`. - */ - private int maxRefRank(ReachableBasicBlock bb, SsaSourceVariable v) { - result = max(refRank(bb, _, v, _)) - } +final private class NativeDefinition = Shared::Definition; - /** - * Holds if variable `v` is live after the `i`th node of basic block `bb`, where - * `i` is the index of a node that may assign or capture `v`. - * - * For the purposes of this predicate, `yield` expressions and function invocations - * are considered as writes of captured variables. - */ - private predicate liveAfterDef(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - exists(int r | r = refRank(bb, i, v, Write()) | - // the next reference to `v` inside `bb` is a read - r + 1 = refRank(bb, _, v, Read()) - or - // this is the last reference to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - r = maxRefRank(bb, v) and - liveAtSuccEntry(bb, v) - ) - } - - /** - * Holds if variable `v` is live at the beginning of basic block `bb`. - * - * For the purposes of this predicate, `yield` expressions and function invocations - * are considered as writes of captured variables. - */ - private predicate liveAtEntry(ReachableBasicBlock bb, SsaSourceVariable v) { - // the first reference to `v` inside `bb` is a read - refRank(bb, _, v, Read()) = 1 - or - // there is no reference to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - not exists(refRank(bb, _, v, _)) and - liveAtSuccEntry(bb, v) - } - - /** - * Holds if `v` is live at the beginning of any successor of basic block `bb`. - */ - private predicate liveAtSuccEntry(ReachableBasicBlock bb, SsaSourceVariable v) { - liveAtEntry(bb.getASuccessor(), v) - } - - /** - * Holds if `v` is assigned outside its declaring function. - */ - private predicate assignedThroughClosure(SsaSourceVariable v) { - v.getAnAccess().(LValue).getContainer() != v.getDeclaringContainer() - } - - /** - * Holds if the `i`th node of `bb` is a use or an SSA definition of variable `v`, with - * `k` indicating whether it is the former or the latter. - */ - private predicate ssaRef(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind k) { - bb.useAt(i, v, _) and k = Read() - or - any(SsaDefinition def).definesAt(bb, i, v) and k = Write() - } - - /** - * Gets the (1-based) rank of the `i`th node of `bb` among all SSA definitions - * and uses of `v` in `bb`, with `k` indicating whether it is a definition or a use. - * - * For example, if `bb` is a basic block with a phi node for `v` (considered - * to be at index -1), uses `v` at node 2 and defines it at node 5, we have: - * - * ``` - * ssaRefRank(bb, -1, v, Write()) = 1 // phi node - * ssaRefRank(bb, 2, v, Read()) = 2 // use at node 2 - * ssaRefRank(bb, 5, v, Write()) = 3 // definition at node 5 - * ``` - */ - private int ssaRefRank(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind k) { - i = rank[result](int j | ssaRef(bb, j, v, _)) and - ssaRef(bb, i, v, k) - } - - /** - * Gets the minimum rank of a read in `bb` such that all references to `v` between that - * read and the read at index `i` are reads (and not writes). - */ - private int rewindReads(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - exists(int r | r = ssaRefRank(bb, i, v, Read()) | - exists(int j, RefKind k | r - 1 = ssaRefRank(bb, j, v, k) | - k = Read() and result = rewindReads(bb, j, v) - or - k = Write() and result = r - ) - or - r = 1 and result = r - ) - } - - /** - * Gets the SSA definition of `v` in `bb` that reaches the read of `v` at node `i`, if any. - */ - private SsaDefinition getLocalDefinition(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - exists(int r | r = rewindReads(bb, i, v) | - exists(int j | result.definesAt(bb, j, v) and ssaRefRank(bb, j, v, _) = r - 1) - ) - } - - /** - * Gets an SSA definition of `v` that reaches the end of the immediate dominator of `bb`. - */ - pragma[noinline] - private SsaDefinition getDefReachingEndOfImmediateDominator( - ReachableBasicBlock bb, SsaSourceVariable v - ) { - result = getDefReachingEndOf(bb.getImmediateDominator(), v) - } - - /** - * Gets an SSA definition of `v` that reaches the end of basic block `bb`. - */ - cached - SsaDefinition getDefReachingEndOf(ReachableBasicBlock bb, SsaSourceVariable v) { - Stages::DataFlowStage::ref() and - exists(int lastRef | lastRef = max(int i | ssaRef(bb, i, v, _)) | - result = getLocalDefinition(bb, lastRef, v) - or - result.definesAt(bb, lastRef, v) and - liveAtSuccEntry(bb, v) - ) - or - /* - * In SSA form, the (unique) reaching definition of a use is the closest - * definition that dominates the use. If two definitions dominate a node - * then one must dominate the other, so we can find the reaching definition - * by following the idominance relation backwards. - */ - - result = getDefReachingEndOfImmediateDominator(bb, v) and - not exists(SsaDefinition ssa | ssa.definesAt(bb, _, v)) and - liveAtSuccEntry(bb, v) - } - - /** - * Gets the unique SSA definition of `v` whose value reaches the `i`th node of `bb`, - * which is a use of `v`. - */ - cached - SsaDefinition getDefinition(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - result = getLocalDefinition(bb, i, v) - or - rewindReads(bb, i, v) = 1 and result = getDefReachingEndOf(bb.getImmediateDominator(), v) - } -} - -private import Internal - -/** - * An SSA variable. - */ -class SsaVariable extends TSsaDefinition { +/** An SSA variable, represented by its shared SSA definition. */ +class SsaVariable instanceof SsaDefinition { /** Gets the source variable corresponding to this SSA variable. */ - SsaSourceVariable getSourceVariable() { result = this.(SsaDefinition).getSourceVariable() } + SsaSourceVariable getSourceVariable() { result = this.getDefinition().getSourceVariable() } - /** Gets the (unique) definition of this SSA variable. */ + /** Gets the unique definition of this SSA variable. */ SsaDefinition getDefinition() { result = this } /** Gets a use in basic block `bb` that refers to this SSA variable. */ VarUse getAUseIn(ReachableBasicBlock bb) { - exists(int i, SsaSourceVariable v | v = this.getSourceVariable() | - bb.useAt(i, v, result) and this = getDefinition(bb, i, v) + exists(int i, Shared::SsaConfig::SourceVariable variable | + variable.asLocalVariable() = this.getSourceVariable() and + bb.useAt(i, this.getSourceVariable(), result) and + Shared::ssaDefReachesRead(variable, this, bb, i) ) } @@ -417,15 +49,7 @@ class SsaVariable extends TSsaDefinition { /** Gets the location of this SSA variable. */ Location getLocation() { result = this.getDefinition().getLocation() } - /** - * DEPRECATED. Use `getLocation().hasLocationInfo()` instead. - * - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ + /** DEPRECATED. Use `getLocation().hasLocationInfo()` instead. */ deprecated predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { @@ -433,66 +57,48 @@ class SsaVariable extends TSsaDefinition { } } -/** - * An SSA definition. - */ -class SsaDefinition extends TSsaDefinition { +/** An SSA definition backed by the shared SSA implementation. */ +class SsaDefinition instanceof NativeDefinition { + SsaDefinition() { exists(this.(NativeDefinition).getSourceVariable().asLocalVariable()) } + /** Gets the SSA variable defined by this definition. */ SsaVariable getVariable() { result = this } /** Gets the source variable defined by this definition. */ - abstract SsaSourceVariable getSourceVariable(); + SsaSourceVariable getSourceVariable() { + result = this.(NativeDefinition).getSourceVariable().asLocalVariable() + } - /** - * Gets the basic block to which this definition belongs. - * - * Currently, all SSA definitions belong to a basic block, but the representation of - * implicit definitions might change in the future, making this no longer true. - */ - abstract ReachableBasicBlock getBasicBlock(); + /** Gets the basic block to which this definition belongs. */ + ReachableBasicBlock getBasicBlock() { result = this.(NativeDefinition).getBasicBlock() } /** * INTERNAL: Use `getBasicBlock()` and `getSourceVariable()` instead. * - * Holds if this is a definition of source variable `v` at index `idx` in basic block `bb`. - * - * Phi nodes are considered to be at index `-1`, all other definitions at the index of - * the control flow node they correspond to. - */ - abstract predicate definesAt(ReachableBasicBlock bb, int idx, SsaSourceVariable v); + * Holds if this defines `v` at index `idx` in `bb`. Implicit initializations + * retain their JavaScript API index of zero; shared SSA stores them at -1. + */ + predicate definesAt(ReachableBasicBlock bb, int idx, SsaSourceVariable v) { + exists(Shared::SsaConfig::SourceVariable variable, int nativeIndex | + this.(NativeDefinition).definesAt(variable, bb, nativeIndex) and + variable.asLocalVariable() = v and + if this instanceof SsaImplicitInit then idx = 0 else idx = nativeIndex + ) + } - /** - * Gets a variable definition node whose value may end up contributing - * to the SSA variable defined by this definition. - */ + /** Gets a variable definition contributing to this SSA definition. */ abstract VarDef getAContributingVarDef(); - /** - * INTERNAL: Use `toString()` instead. - * - * Gets a pretty-printed representation of this SSA definition. - */ + /** INTERNAL: Use `toString()` instead. */ abstract string prettyPrintDef(); - /** - * INTERNAL: Do not use. - * - * Gets a pretty-printed representation of a reference to this SSA definition. - */ + /** INTERNAL: Do not use. */ abstract string prettyPrintRef(); /** Gets a textual representation of this element. */ string toString() { result = this.prettyPrintDef() } - /** - * DEPRECATED. Use `getLocation().hasLocationInfo()` instead. - * - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ + /** DEPRECATED. Use `getLocation().hasLocationInfo()` instead. */ deprecated predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { @@ -506,33 +112,42 @@ class SsaDefinition extends TSsaDefinition { StmtContainer getContainer() { result = this.getBasicBlock().getContainer() } } -/** - * An SSA definition that corresponds to an explicit assignment or other variable definition. - */ -class SsaExplicitDefinition extends SsaDefinition, TExplicitDef { - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - this = TExplicitDef(bb, i, _, v, _) +/** An SSA definition corresponding to an explicit variable definition. */ +class SsaExplicitDefinition extends SsaDefinition { + SsaExplicitDefinition() { + exists(Shared::SsaConfig::SourceVariable variable, BasicBlock bb, int i | + this.(Shared::WriteDefinition).definesAt(variable, bb, i) and + bb.defAt(i, variable.asLocalVariable(), _) + ) } - /** This SSA definition corresponds to the definition of `v` at `def`. */ - predicate defines(VarDef def, SsaSourceVariable v) { this = TExplicitDef(_, _, def, v, _) } + /** Holds if this corresponds to the definition of `v` at `def`. */ + predicate defines(VarDef def, SsaSourceVariable v) { + def = this.getDef() and v = this.getSourceVariable() + } /** Gets the variable definition wrapped by this SSA definition. */ - VarDef getDef() { this = TExplicitDef(_, _, result, _, _) } - - /** Gets the variable reference appearing on the left-hand side of this assignment. */ - VarRef getLhs() { this = TExplicitDef(_, _, _, _, result) } - - /** Gets the basic block to which this definition belongs. */ - override ReachableBasicBlock getBasicBlock() { this.definesAt(result, _, _) } + VarDef getDef() { + exists(Shared::SsaConfig::SourceVariable variable, BasicBlock bb, int i | + this.(Shared::WriteDefinition).definesAt(variable, bb, i) and + bb.defAt(i, variable.asLocalVariable(), result) + ) + } - override SsaSourceVariable getSourceVariable() { this = TExplicitDef(_, _, _, result, _) } + /** Gets the variable reference on the left-hand side of this assignment. */ + VarRef getLhs() { + exists(Shared::SsaConfig::SourceVariable variable, BasicBlock bb, int i | + this.(Shared::WriteDefinition).definesAt(variable, bb, i) and + bb.defAt(i, variable.asLocalVariable(), this.getDef(), result) + ) + } override VarDef getAContributingVarDef() { result = this.getDef() } override string prettyPrintRef() { - exists(int l, int c | this.getLocation().hasLocationInfo(_, l, c, _, _) | - result = "def@" + l + ":" + c + exists(int line, int column | + this.getLocation().hasLocationInfo(_, line, column, _, _) and + result = "def@" + line + ":" + column ) } @@ -540,45 +155,28 @@ class SsaExplicitDefinition extends SsaDefinition, TExplicitDef { override Location getLocation() { result = this.getLhs().getLocation() } - /** - * Gets the data flow node representing the incoming value assigned at this definition, - * if any. - */ + /** Gets the incoming value assigned at this definition, if any. */ DataFlow::Node getRhsNode() { result = DataFlow::ssaDefinitionNode(this).getImmediatePredecessor() } } -/** - * An SSA definition that does not correspond to an explicit variable definition. - */ +/** An SSA definition that does not correspond to an explicit variable definition. */ abstract class SsaImplicitDefinition extends SsaDefinition { - /** - * INTERNAL: Do not use. - * - * Gets the definition kind to include in `prettyPrintRef`. - */ + /** INTERNAL: Gets the definition kind used in `prettyPrintRef`. */ abstract string getKind(); override string prettyPrintRef() { - exists(int l, int c | this.getLocation().hasLocationInfo(_, l, c, _, _) | - result = this.getKind() + "@" + l + ":" + c + exists(int line, int column | + this.getLocation().hasLocationInfo(_, line, column, _, _) and + result = this.getKind() + "@" + line + ":" + column ) } } -/** - * An SSA definition representing the implicit initialization of a variable - * at the beginning of its scope. - */ -class SsaImplicitInit extends SsaImplicitDefinition, TImplicitInit { - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - bb = this.getBasicBlock() and v = this.getSourceVariable() and i = 0 - } - - override ReachableBasicBlock getBasicBlock() { this = TImplicitInit(result, _) } - - override SsaSourceVariable getSourceVariable() { this = TImplicitInit(_, result) } +/** The implicit initialization of a variable at the beginning of its scope. */ +class SsaImplicitInit extends SsaImplicitDefinition { + SsaImplicitInit() { this.(Shared::WriteDefinition).definesAt(_, any(EntryBasicBlock bb), -1) } override string getKind() { result = "implicitInit" } @@ -589,21 +187,9 @@ class SsaImplicitInit extends SsaImplicitDefinition, TImplicitInit { } } -/** - * An SSA definition representing the capturing of an SSA-convertible variable - * in the closure of a nested function. - * - * Capturing definitions appear at the beginning of such functions, as well as - * at any `yield` expressions or calls that may affect the value of the variable. - */ -class SsaVariableCapture extends SsaImplicitDefinition, TCapture { - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - this = TCapture(bb, i, v) - } - - override ReachableBasicBlock getBasicBlock() { this.definesAt(result, _, _) } - - override SsaSourceVariable getSourceVariable() { this.definesAt(_, _, result) } +/** A conservative capture or recapture of a variable from an enclosing scope. */ +class SsaVariableCapture extends SsaImplicitDefinition { + SsaVariableCapture() { Shared::isCaptureDefinition(this) } override VarDef getAContributingVarDef() { result.getAVariable() = this.getSourceVariable() } @@ -612,16 +198,9 @@ class SsaVariableCapture extends SsaImplicitDefinition, TCapture { override string prettyPrintDef() { result = "capture variable " + this.getSourceVariable() } } -/** - * An SSA definition that has no actual semantics, but simply serves to - * merge or filter data flow. - * - * Phi nodes are the canonical example. - */ +/** A definition that merges or refines incoming SSA values. */ abstract class SsaPseudoDefinition extends SsaImplicitDefinition { - /** - * Gets an input of this pseudo-definition. - */ + /** Gets an input of this pseudo-definition. */ cached abstract SsaVariable getAnInput(); @@ -629,99 +208,55 @@ abstract class SsaPseudoDefinition extends SsaImplicitDefinition { result = this.getAnInput().getDefinition().getAContributingVarDef() } - /** - * Gets a textual representation of the inputs of this pseudo-definition - * in lexicographical order. - */ + /** Gets a textual representation of the inputs in lexicographical order. */ string ppInputs() { result = concat(this.getAnInput().getDefinition().prettyPrintRef(), ", ") } } -/** - * An SSA phi node, that is, a pseudo-definition for a variable at a point - * in the flow graph where otherwise two or more definitions for the variable - * would be visible. - */ -class SsaPhiNode extends SsaPseudoDefinition, TPhi { - /** - * Gets the input to this phi node coming from the given predecessor block. - */ +/** A phi definition from the shared SSA implementation. */ +class SsaPhiNode extends SsaPseudoDefinition instanceof Shared::PhiNode { + /** Gets the input arriving from predecessor block `bb`. */ cached - SsaVariable getInputFromBlock(BasicBlock bb) { - bb = this.getBasicBlock().getAPredecessor() and - result = getDefReachingEndOf(bb, this.getSourceVariable()) - } + SsaVariable getInputFromBlock(BasicBlock bb) { Shared::phiHasInputFromBlock(this, result, bb) } override SsaVariable getAnInput() { result = this.getInputFromBlock(_) } - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - bb = this.getBasicBlock() and v = this.getSourceVariable() and i = -1 - } - - override ReachableBasicBlock getBasicBlock() { this = TPhi(result, _) } - - override SsaSourceVariable getSourceVariable() { this = TPhi(_, result) } - override string getKind() { result = "phi" } override string prettyPrintDef() { result = this.getSourceVariable() + " = phi(" + this.ppInputs() + ")" } - /** - * If all inputs to this phi node are (transitive) refinements of the same variable, - * gets that variable. - */ + /** Gets the variable of which all inputs are transitive refinements, if any. */ SsaVariable getRephinedVariable() { forex(SsaVariable input | input = this.getAnInput() | result = getRefinedVariable(input)) } } -/** - * Gets the input to the given refinement node or rephinement node. - */ -private SsaVariable getRefinedVariable(SsaVariable v) { - result = getRefinedVariable(v.(SsaRefinementNode).getAnInput()) +private SsaVariable getRefinedVariable(SsaVariable variable) { + result = getRefinedVariable(variable.(SsaRefinementNode).getAnInput()) or - result = getRefinedVariable(v.(SsaPhiNode).getRephinedVariable()) + result = getRefinedVariable(variable.(SsaPhiNode).getRephinedVariable()) or - not v instanceof SsaRefinementNode and - not v instanceof SsaPhiNode and - result = v + not variable instanceof SsaRefinementNode and + not variable instanceof SsaPhiNode and + result = variable } -/** - * A refinement node, that is, a pseudo-definition for a variable at a point - * in the flow graph where additional information about this variable becomes - * available that may restrict its possible set of values. - */ -class SsaRefinementNode extends SsaPseudoDefinition, TRefinement { - /** - * Gets the guard that induces this refinement. - */ - GuardControlFlowNode getGuard() { this = TRefinement(_, _, result, _) } +/** A shared uncertain write preserving the incoming value under a refinement. */ +class SsaRefinementNode extends SsaPseudoDefinition { + SsaRefinementNode() { Shared::isRefinementDefinition(this) } - /** - * Gets the refinement associated with this definition. - */ - Refinement getRefinement() { result = this.getGuard().getTest() } - - override SsaVariable getAnInput() { - exists(SsaSourceVariable v, BasicBlock bb | - v = this.getSourceVariable() and bb = this.getBasicBlock() - | - if exists(SsaPhiNode phi | phi.definesAt(bb, _, v)) - then result.(SsaPhiNode).definesAt(bb, _, v) - else result = getDefReachingEndOf(bb.getAPredecessor(), v) + /** Gets the guard inducing this refinement. */ + GuardControlFlowNode getGuard() { + exists(BasicBlock bb, int i | + this.(NativeDefinition).definesAt(_, bb, i) and result = bb.getNode(i) ) } - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - this = TRefinement(bb, i, _, v) - } - - override ReachableBasicBlock getBasicBlock() { this = TRefinement(result, _, _, _) } + /** Gets the refinement associated with this definition. */ + Refinement getRefinement() { result = this.getGuard().getTest() } - override SsaSourceVariable getSourceVariable() { this = TRefinement(_, _, _, result) } + override SsaVariable getAnInput() { Shared::uncertainWriteDefinitionInput(this, result) } override string getKind() { result = "refine[" + this.getGuard() + "]" } @@ -734,7 +269,7 @@ class SsaRefinementNode extends SsaPseudoDefinition, TRefinement { } module Ssa { - /** Gets the SSA definition corresponding to the implicit initialization of `v`. */ + /** Gets the definition of the implicit initialization of `v`. */ SsaImplicitInit implicitInit(SsaSourceVariable v) { result.getSourceVariable() = v } /** Gets the SSA definition corresponding to `d`. */ diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll index ffbb9e497b04..210e63a3e196 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll @@ -525,7 +525,12 @@ deprecated private predicate barrierGuardBlocksEdge( SsaVariable input, SsaPhiNode phi, BasicBlock bb, ConditionGuardNode cond, boolean outcome | bb = getADominatedBasicBlock(guard, cond) and - pred = DataFlow::ssaDefinitionNode(input) and + ( + pred = DataFlow::ssaDefinitionNode(input) + or + pred = succ.getAPredecessor() and + pred.getBasicBlock() = bb + ) and succ = DataFlow::ssaDefinitionNode(phi) and input = phi.getInputFromBlock(bb) and outcome = cond.getOutcome() and diff --git a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll index a24d7976b3d6..a692a80e4ad6 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll @@ -32,6 +32,7 @@ private import semmle.javascript.dataflow.internal.VariableOrThis private import semmle.javascript.internal.NameResolution private import semmle.javascript.internal.UnderlyingTypes private import semmle.javascript.internal.TypeResolution +private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2 module DataFlow { /** @@ -279,10 +280,15 @@ module DataFlow { /** * A node in the data flow graph which corresponds to an SSA variable definition. */ - class SsaDefinitionNode extends Node, TSsaDefNode { + class SsaDefinitionNode extends Node { SsaDefinition ssa; - SsaDefinitionNode() { this = TSsaDefNode(ssa) } + SsaDefinitionNode() { + exists(Ssa2::SsaConfig::SourceVariable var, BasicBlock bb, int index | + this = TSharedSsaDefNode(var, bb, index) and + ssa.(Ssa2::Definition).definesAt(var, bb, index) + ) + } /** Gets the SSA variable defined at this data flow node. */ SsaVariable getSsaVariable() { result = ssa.getVariable() } @@ -1441,7 +1447,14 @@ module DataFlow { ExprNode exprNode(Expr e) { result = valueNode(e) } /** Gets the data flow node corresponding to `ssa`. */ - SsaDefinitionNode ssaDefinitionNode(SsaDefinition ssa) { result = TSsaDefNode(ssa) } + SsaDefinitionNode ssaDefinitionNode(SsaDefinition ssa) { result = ssaDefinitionNodeInternal(ssa) } + + private EarlyStageNode ssaDefinitionNodeInternal(SsaDefinition ssa) { + exists(BasicBlock bb, int i, Ssa2::SsaConfig::SourceVariable var | + ssa.(Ssa2::Definition).definesAt(var, bb, i) and + result = TSharedSsaDefNode(var, bb, i) + ) + } /** Gets the node corresponding to the initialization of parameter `p`. */ ParameterNode parameterNode(Parameter p) { result.getParameter() = p } @@ -1525,9 +1538,11 @@ module DataFlow { * before all data flow nodes have been materialised. */ EarlyStageNode lvalueNodeInternal(BindingPattern lvalue) { - exists(SsaExplicitDefinition ssa | - ssa.defines(lvalue.(LValue).getDefNode(), lvalue.(VarRef).getVariable()) and - result = TSsaDefNode(ssa) + exists(Ssa2::Definition ssa, BasicBlock bb, int i, Ssa2::SsaConfig::SourceVariable var | + ssa.definesAt(var, bb, i) and + var.asLocalVariable() = lvalue.(VarRef).getVariable() and + bb.defAt(i, var.asLocalVariable(), lvalue.(LValue).getDefNode(), lvalue) and + result = TSharedSsaDefNode(var, bb, i) ) or result = TValueNode(lvalue.(DestructuringPattern)) @@ -1579,8 +1594,8 @@ module DataFlow { ) or exists(SimpleParameter param | - pred = TValueNode(param) and // The value node represents the incoming argument - succ = lvalueNodeInternal(param) // The SSA node represents the parameters's local variable + pred = TValueNode(param) and + succ = lvalueNodeInternal(param) ) or exists(Expr arg, Parameter param | @@ -1626,18 +1641,69 @@ module DataFlow { ) } - /** - * Flow steps shared between `immediateFlowStep` and `localFlowStep`. - * - * Inlining is forced because the two relations are indexed differently. - */ + private predicate sharedTypeInferenceFlowStep(Ssa2::Node pred, Ssa2::Node succ) { + exists(boolean isUseStep, Ssa2::SsaConfig::SourceVariable variable | + Ssa2::localFlowStep(variable, pred, succ, isUseStep) and + not variable.isCaptured() and + ( + isUseStep = false + or + isUseStep = true and + not sharedReadInsideWith(pred) + ) + ) + or + exists(Ssa2::Node dynamicRead | + sharedReadInsideWith(dynamicRead) and + Ssa2::localFlowStep(_, dynamicRead, succ, true) and + sharedTypeInferenceFlowStep(pred, dynamicRead) + ) + } + + private predicate sharedReadInsideWith(Ssa2::Node node) { + exists(Ssa2::ExprNode read, WithStmt with | + node = read and + not Ssa2::isPostUpdateRead(read) and + read.getExpr().(AstNode).getParent+() = with.getBody() + ) + } + + private predicate sharedImmediateFlowStep(Ssa2::Node pred, Ssa2::Node succ) { + Ssa2::localMustFlowStep(_, pred, succ) + } + + private predicate sharedPhiImmediateFlowStep(EarlyStageNode pred, EarlyStageNode succ) { + exists(SsaPhiNode phi | + not phi.getSourceVariable().isCaptured() and + pred = ssaDefinitionNodeInternal(phi.getRephinedVariable().getDefinition()) and + succ = ssaDefinitionNodeInternal(phi) + ) + } + + private predicate ordinaryFlowStepShared(EarlyStageNode pred, EarlyStageNode succ) { + exists(Ssa2::Node ssaPred, Ssa2::Node ssaSucc, Ssa2::SsaConfig::SourceVariable variable | + Ssa2::localFlowStep(variable, ssaPred, ssaSucc, _) and + not variable.isCaptured() and + pred = getNodeFromSharedSsa(ssaPred) and + succ = getNodeFromSharedSsa(ssaSucc) and + pred != succ + ) + } + pragma[inline] - private predicate immediateFlowStepShared(EarlyStageNode pred, EarlyStageNode succ) { - exists(SsaVariable v | - pred = TSsaDefNode(v.getDefinition()) and - succ = TValueNode(v.getAUse()) + private predicate sharedSsaImmediateFlowStep(EarlyStageNode pred, EarlyStageNode succ) { + exists(Ssa2::Node ssaPred, Ssa2::Node ssaSucc | + sharedImmediateFlowStep(ssaPred, ssaSucc) and + pred = getNodeFromSharedSsa(ssaPred) and + succ = getNodeFromSharedSsa(ssaSucc) and + pred != succ ) or + sharedPhiImmediateFlowStep(pred, succ) + } + + pragma[inline] + private predicate nonSsaImmediateFlowStep(EarlyStageNode pred, EarlyStageNode succ) { exists(Expr predExpr, Expr succExpr | pred = TValueNode(predExpr) and succ = TValueNode(succExpr) | @@ -1666,8 +1732,12 @@ module DataFlow { ) ) or - // flow from 'this' parameter into 'this' expressions + // flow from 'this' parameter into 'this' expressions when not handled by shared SSA exists(ThisExpr thiz | + ( + LocalVariableOrThis::thisInContainer(thiz.getBindingContainer()).isCaptured() or + not thiz.getBasicBlock() instanceof ReachableBasicBlock + ) and pred = TThisNode(thiz.getBindingContainer()) and succ = TValueNode(thiz) ) @@ -1678,11 +1748,28 @@ module DataFlow { succ = TValueNode(call) ) or - // Pass 'this' into implicit uses of 'this' + // Pass 'this' into implicit uses of 'this' when not handled by shared SSA exists(ImplicitThisUse use | + ( + LocalVariableOrThis::thisInContainer(use.getBindingContainer()).isCaptured() or + not use.(ControlFlowNode).getBasicBlock() instanceof ReachableBasicBlock + ) and pred = TThisNode(use.getBindingContainer()) and succ = TImplicitThisUse(use, false) ) + or + exists(SsaVariable captured | + captured.getSourceVariable().isCaptured() and + pred = capturedSsaNode(captured.getDefinition()) and + succ = TValueNode(captured.getAUse()) + ) + } + + pragma[inline] + private predicate immediateFlowStepShared(EarlyStageNode pred, EarlyStageNode succ) { + sharedSsaImmediateFlowStep(pred, succ) + or + nonSsaImmediateFlowStep(pred, succ) } pragma[nomagic] @@ -1692,15 +1779,12 @@ module DataFlow { or immediateFlowStepShared(pred, succ) or - // Refinement of variable -> original definition of variable - exists(SsaRefinementNode refinement | - succ = TSsaDefNode(refinement) and - pred = TSsaDefNode(refinement.getAnInput()) - ) + refinementFlowStep(pred, succ, true) or exists(SsaPhiNode phi | - succ = TSsaDefNode(phi) and - pred = TSsaDefNode(phi.getRephinedVariable()) + phi.getSourceVariable().isCaptured() and + succ = capturedSsaNode(phi) and + pred = capturedSsaNode(phi.getRephinedVariable()) ) or // IIFE call -> return value of IIFE @@ -1712,38 +1796,36 @@ module DataFlow { ) } - /** - * Holds if data can flow from `pred` to `succ` in one local step. - */ cached - predicate localFlowStep(EarlyStageNode pred, EarlyStageNode succ) { + private predicate localFlowStepWithoutSharedOrdinary(EarlyStageNode pred, EarlyStageNode succ) { Stages::EarlyDataFlowStage::ref() and // flow from RHS into LHS lvalueFlowStep(pred, succ) or lvalueDefaultFlowStep(pred, succ) or - immediateFlowStepShared(pred, succ) + nonSsaImmediateFlowStep(pred, succ) + or + refinementFlowStep(pred, succ, false) or - // From an assignment or implicit initialization of a captured variable to its flow-insensitive node. exists(SsaDefinition predDef | - pred = TSsaDefNode(predDef) and + predDef.getSourceVariable().isCaptured() and + pred = capturedSsaNode(predDef) and succ = TCapturedVariableNode(predDef.getSourceVariable()) | predDef instanceof SsaExplicitDefinition or predDef instanceof SsaImplicitInit ) or - // From a captured variable node to its flow-sensitive capture nodes - exists(SsaVariableCapture ssaCapture | - pred = TCapturedVariableNode(ssaCapture.getSourceVariable()) and - succ = TSsaDefNode(ssaCapture) + exists(SsaVariableCapture capture | + pred = TCapturedVariableNode(capture.getSourceVariable()) and + succ = capturedSsaNode(capture) ) or - // Flow through implicit SSA nodes - exists(SsaImplicitDefinition ssa | succ = TSsaDefNode(ssa) | - // from the inputs of phi and pi nodes into the node itself - pred = TSsaDefNode(ssa.(SsaPseudoDefinition).getAnInput().getDefinition()) + exists(SsaImplicitDefinition ssa | + ssa.getSourceVariable().isCaptured() and + succ = capturedSsaNode(ssa) and + pred = capturedSsaNode(ssa.(SsaPseudoDefinition).getAnInput().getDefinition()) ) or exists(Expr predExpr, Expr succExpr | @@ -1775,6 +1857,39 @@ module DataFlow { ) } + /** + * Holds if data can flow from `pred` to `succ` in one local step. + */ + cached + predicate localFlowStep(EarlyStageNode pred, EarlyStageNode succ) { + localFlowStepWithoutSharedOrdinary(pred, succ) + or + ordinaryFlowStepShared(pred, succ) + } + + /** + * INTERNAL: Local flow steps imported by global flow. Shared SSA flow is imported separately. + */ + predicate localFlowStepForGlobal(EarlyStageNode pred, EarlyStageNode succ) { + localFlowStepWithoutSharedOrdinary(pred, succ) + } + + /** + * INTERNAL: Local steps for value inference. Skip intermediate reads in `with` + * statements so their reflective uncertainty does not propagate to later reads. + * Security flow must instead visit those reads so their barriers remain effective. + */ + predicate localFlowStepForTypeInference(EarlyStageNode pred, EarlyStageNode succ) { + localFlowStepWithoutSharedOrdinary(pred, succ) + or + exists(Ssa2::Node ssaPred, Ssa2::Node ssaSucc | + sharedTypeInferenceFlowStep(ssaPred, ssaSucc) and + pred = getNodeFromSharedSsa(ssaPred) and + succ = getNodeFromSharedSsa(ssaSucc) and + pred != succ + ) + } + overlay[global] private class ReflectiveParamsStep extends LegacyPreCallGraphStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { @@ -1823,6 +1938,83 @@ module DataFlow { result = def.getDestructuringSource() } + private predicate refinementFlowStep(EarlyStageNode pred, EarlyStageNode succ, boolean immediate) { + exists(SsaRefinementNode refinement | + ( + immediate = true + or + immediate = false and refinement.getSourceVariable().isCaptured() + ) and + pred = ssaDefinitionNodeInternal(refinement.getAnInput().getDefinition()) and + succ = ssaDefinitionNodeInternal(refinement) + ) + } + + private EarlyStageNode capturedSsaNode(SsaDefinition ssa) { + ssa.getSourceVariable().isCaptured() and + result = ssaDefinitionNodeInternal(ssa) + } + + /** INTERNAL: Gets the JavaScript data flow node corresponding to a shared SSA node. */ + cached + EarlyStageNode getNodeFromSharedSsa(Ssa2::Node node) { + exists(Ssa2::ExprNode read | + node = read and + not Ssa2::isPostUpdateRead(read) and + not read.getExpr() instanceof ImplicitThisUse and + result = TValueNode(read.getExpr()) + ) + or + exists(Ssa2::ExprNode read, ImplicitThisUse use | + node = read and + read.getExpr() = use and + result = TImplicitThisUse(use, false) + ) + or + exists(Ssa2::ExprPostUpdateNode post | + node = post and + not Ssa2::isPostUpdateRead(post.getPreUpdateNode()) and + not post.getExpr() instanceof ImplicitThisUse and + result = TExprPostUpdateNode(post.getExpr()) + ) + or + exists(ImplicitThisUse use | + node.(Ssa2::ExprPostUpdateNode).getExpr() = use and + result = TImplicitThisUse(use, true) + ) + or + result = TSsaSynthReadNode(node) + or + exists(Ssa2::Definition def, Ssa2::SsaConfig::SourceVariable var, BasicBlock bb, int i | + node.(Ssa2::SsaDefinitionNode).getDefinition() = def and + def.definesAt(var, bb, i) and + result = TSharedSsaDefNode(var, bb, i) + ) + or + exists(Ssa2::Definition def, Ssa2::SsaConfig::SourceVariable var, BasicBlock bb | + node.(Ssa2::SsaDefinitionNode).getDefinition() = def and + def.definesAt(var, bb, -1) and + result = TThisNode(var.asThisContainer()) + ) + or + exists( + Ssa2::WriteDefinition def, Ssa2::SsaConfig::SourceVariable var, BasicBlock bb, int i, + VarDef write + | + node.(Ssa2::WriteDefSourceNode).getDefinition() = def and + def.definesAt(var, bb, i) and + bb.defAt(i, var.asLocalVariable(), write) and + write.getTarget() instanceof VarRef and + result = TValueNode(write.getSource()) + ) + or + exists(Ssa2::WriteDefinition def, Ssa2::SsaConfig::SourceVariable var, EntryBasicBlock bb | + node.(Ssa2::WriteDefSourceNode).getDefinition() = def and + def.definesAt(var, bb, -1) and + result = TThisNode(var.asThisContainer()) + ) + } + /** * Holds if the flow information for the node `nd`. * @@ -1837,7 +2029,7 @@ module DataFlow { */ overlay[global] predicate isIncomplete(Node nd, Incompleteness cause) { - exists(SsaVariable ssa | nd = TSsaDefNode(ssa.getDefinition()) | + exists(SsaVariable ssa | nd = ssaDefinitionNode(ssa.getDefinition()) | defIsIncomplete(ssa.(SsaExplicitDefinition).getDef(), cause) or exists(Variable v | v = ssa.getSourceVariable() | diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TypeInference.qll b/javascript/ql/lib/semmle/javascript/dataflow/TypeInference.qll index a5e686a90c25..6556331dba93 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TypeInference.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TypeInference.qll @@ -40,10 +40,10 @@ import internal.VariableTypeInference */ class AnalyzedNode extends DataFlow::Node { /** - * Gets another data flow node whose value flows into this node in one local step - * (that is, not involving global variables). + * Gets a predecessor used for local value inference, without propagating + * reflective uncertainty out of reads in `with` statements. */ - AnalyzedNode localFlowPred() { result = this.getAPredecessor() } + AnalyzedNode localFlowPred() { DataFlow::localFlowStepForTypeInference(result, this) } /** * Gets an abstract value that this node may evaluate to at runtime. diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/BarrierGuards.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/BarrierGuards.qll index 699cfd94fbbc..7a47ac5ca8b9 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/BarrierGuards.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/BarrierGuards.qll @@ -335,8 +335,10 @@ module MakeStateBarrierGuard< Ssa2::SsaDataflowInput::Guard guard, Ssa2::SsaDataflowInput::Expr test, Boolean branch, FlowState state ) { - exists(BarrierGuard g | - g.asExpr() = guard and + exists(BarrierGuard g, ConditionGuardNode cond | + cond.getTest() = guard and + barrierGuardUsedInCondition(g, cond, branch) and + Ssa2::isExplicitRead(test) and g.blocksExpr(branch, test, state) ) } @@ -386,7 +388,15 @@ module MakeStateBarrierGuard< or exists(Expr use | barrierGuardBlocksAccessPathUse(use, state) and - nd = DataFlow::valueNode(use) + ( + nd = DataFlow::valueNode(use) + or + exists(Ssa2::ExprNode read | + read.getExpr() = use and + not Ssa2::isPostUpdateRead(read) and + nd = DataFlowPrivate::getNodeFromSsa2(read) + ) + ) ) or ssa2BlocksNode(nd, state) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll index 315c8706bc00..6c52a41287c5 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -32,12 +32,21 @@ private module Cached { cached newtype TNode = TValueNode(AST::ValueNode nd) or - /** An SSA node from the legacy SSA library */ - TSsaDefNode(SsaDefinition d) or - /** Use of a variable or 'this', with flow from a post-update node (from an earlier use) */ - TSsaUseNode(ControlFlowNode use) { use = any(Ssa2::SsaConfig::SourceVariable v).getAUse() } or - /** A synthesized variable read (new SSA library). Definitions are represented by TSsaDefNode. */ - TSsaSynthReadNode(Ssa2::SsaSynthReadNode read) or + /** An SSA definition from the shared SSA library */ + TSharedSsaDefNode(Ssa2::SsaConfig::SourceVariable v, BasicBlock bb, int i) { + exists(Ssa2::SsaDefinitionNode node | node.getDefinition().definesAt(v, bb, i)) and + exists(v.asLocalVariable()) + } or + /** A synthesized phi input, phi read, or post-update continuation. */ + TSsaSynthReadNode(Ssa2::Node read) { + not read.(Ssa2::SsaSynthReadNode).getSourceVariable().isCaptured() and + (read instanceof Ssa2::SsaSynthReadNode or Ssa2::isPostUpdateRead(read)) + } or + /** The variable or 'this' value at a read, separate from the expression occurrence. */ + TSharedSsaReadNode(Ssa2::ExprNode read) { + not read.getSourceVariable().isCaptured() and + not Ssa2::isPostUpdateRead(read) + } or TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or TPropNode(@property p) or TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or @@ -130,8 +139,8 @@ private module Cached { import Cached private class TEarlyStageNode = - TValueNode or TSsaDefNode or TCapturedVariableNode or TPropNode or TRestPatternNode or - TElementPatternNode or TElementNode or TReflectiveCallNode or TThisNode or + TValueNode or TSharedSsaDefNode or TSsaSynthReadNode or TCapturedVariableNode or TPropNode or + TRestPatternNode or TElementPatternNode or TElementNode or TReflectiveCallNode or TThisNode or TFunctionSelfReferenceNode or TDestructuredModuleImportNode or THtmlAttributeNode or TFunctionReturnNode or TExceptionalFunctionReturnNode or TExceptionalInvocationReturnNode or TGlobalAccessPathRoot or TTemplatePlaceholderTag or TReflectiveParametersNode or diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 1c3eb1dc9e31..ef801fe1495f 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -23,36 +23,60 @@ private class Node = DataFlow::Node; class PostUpdateNode = DataFlow::PostUpdateNode; -class SsaUseNode extends DataFlow::Node, TSsaUseNode { - private ControlFlowNode expr; +class SsaSynthReadNode extends DataFlow::Node, TSsaSynthReadNode { + private Ssa2::Node read; - SsaUseNode() { this = TSsaUseNode(expr) } + SsaSynthReadNode() { this = TSsaSynthReadNode(read) } cached - override string toString() { result = "[ssa-use] " + expr.toString() } + override string toString() { + exists(string variable | + variable = read.(Ssa2::SsaSynthReadNode).getSourceVariable().getName() + or + variable = read.(Ssa2::ExprNode).getSourceVariable().getName() + | + result = "[ssa-synth-read] " + variable + ) + } cached - override StmtContainer getContainer() { result = expr.getContainer() } + override BasicBlock getBasicBlock() { + result = read.(Ssa2::SsaSynthReadNode).getBasicBlock() + or + result = read.(Ssa2::ExprNode).getExpr().getBasicBlock() + } + + cached + override Location getLocation() { result = read.getLocation() } cached - override Location getLocation() { result = expr.getLocation() } + override File getFile() { result = this.getBasicBlock().getFile() } } -class SsaSynthReadNode extends DataFlow::Node, TSsaSynthReadNode { - private Ssa2::SsaSynthReadNode read; +/** A variable or 'this' value at a read that can flow past a barrier on just one expression occurrence. */ +class SharedSsaReadNode extends DataFlow::Node, TSharedSsaReadNode { + private ControlFlowNode read; - SsaSynthReadNode() { this = TSsaSynthReadNode(read) } + SharedSsaReadNode() { + this = TSharedSsaReadNode(any(Ssa2::ExprNode node | node.getExpr() = read)) + } cached - override string toString() { result = "[ssa-synth-read] " + read.getSourceVariable().getName() } + override string toString() { result = "[ssa-read] " + read.toString() } cached override StmtContainer getContainer() { - result = read.getSourceVariable().getDeclaringContainer() + result = read.(ImplicitThisUse).getUseContainer() + or + not read instanceof ImplicitThisUse and + result = read.getBasicBlock().getContainer() } cached override Location getLocation() { result = read.getLocation() } + + cached + override File getFile() { result = read.getFile() } } class FlowSummaryNode extends DataFlow::Node, TFlowSummaryNode { @@ -680,9 +704,9 @@ predicate nodeIsHidden(Node node) { or node instanceof RestParameterStoreNode or - node instanceof SsaUseNode - or node instanceof SsaSynthReadNode + or + node instanceof TSharedSsaReadNode } predicate neverSkipInPathGraph(Node node) { @@ -1140,9 +1164,6 @@ private predicate legacyBarrier(DataFlow::Node node) { node = MakeBarrierGuard::getABarrierNode() } -/** - * Holds if `node` should be removed from the local data flow graph, for compatibility with legacy code. - */ overlay[global] pragma[nomagic] private predicate isBlockedLegacyNode(Node node) { @@ -1201,7 +1222,10 @@ private predicate imprecisePostUpdateStep(DataFlow::PostUpdateNode postUpdate, D */ overlay[global] private predicate valuePreservingStep(Node node1, Node node2) { - node1.getASuccessor() = node2 and + ( + DataFlow::localFlowStepForGlobal(node1, node2) or + sharedSsaFlow(node1, node2) + ) and not isBlockedLegacyNode(node1) and not isBlockedLegacyNode(node2) and not isThisNodeTrackedByVariableCapture(node1) @@ -1221,50 +1245,76 @@ predicate knownSourceModel(Node sink, string model) { none() } predicate knownSinkModel(Node sink, string model) { none() } -private predicate samePhi(SsaPhiNode legacyPhi, Ssa2::PhiNode newPhi) { - exists(BasicBlock bb, LocalVariableOrThis v | - newPhi.definesAt(v, bb, _) and - legacyPhi.definesAt(bb, _, v.asLocalVariable()) - ) -} - cached Node getNodeFromSsa2(Ssa2::Node node) { - result = TSsaUseNode(node.(Ssa2::ExprNode).getExpr()) + result = DataFlow::getNodeFromSharedSsa(node) or - result = TExprPostUpdateNode(node.(Ssa2::ExprPostUpdateNode).getExpr()) + // Guard barriers validate both an occurrence and the variable's continuing value. + result = TSharedSsaReadNode(node) +} + +private Node getSharedSsaFlowNode(Ssa2::Node node) { + result = TSharedSsaReadNode(node) or - exists(ImplicitThisUse use | - node.(Ssa2::ExprPostUpdateNode).getExpr() = use and - result = TImplicitThisUse(use, true) + (not node instanceof Ssa2::ExprNode or Ssa2::isPostUpdateRead(node)) and + result = DataFlow::getNodeFromSharedSsa(node) +} + +/** + * Gets a source that may carry `origin`'s modeled value through call and heap + * steps. These include copying and cloning models, not just object aliases. + */ +private DataFlow::SourceNode modeledPostUpdateValue( + DataFlow::SourceNode origin, DataFlow::TypeTracker tracker +) { + tracker.start() and + result = origin and + exists(Ssa2::ExprNode read | + Ssa2::additionalPostUpdateContinuation(read, _) and + origin = DataFlow::getNodeFromSharedSsa(read).(Node).getALocalSource() ) or - result = TSsaSynthReadNode(node) - or - exists(SsaPhiNode legacyPhi, Ssa2::PhiNode ssaPhi | - node.(Ssa2::SsaDefinitionNode).getDefinition() = ssaPhi and - samePhi(legacyPhi, ssaPhi) and - result = TSsaDefNode(legacyPhi) + exists(DataFlow::TypeTracker previous | + tracker = previous.step(modeledPostUpdateValue(origin, previous), result) ) } -private predicate useUseFlow(Node node1, Node node2) { - exists(Ssa2::Node ssa1, Ssa2::Node ssa2 | - Ssa2::localFlowStep(_, ssa1, ssa2, _) and - node1 = getNodeFromSsa2(ssa1) and - node2 = getNodeFromSsa2(ssa2) and +private predicate modeledPostUpdateFlow(Node node1, Node node2) { + exists( + Ssa2::ExprNode read, Ssa2::ExprNode continuation, Ssa2::ExprPostUpdateNode post, + Ssa2::Node successor, DataFlow::SourceNode origin + | + Ssa2::additionalPostUpdateContinuation(read, continuation) and + post.getPreUpdateNode() = read and + node1 = DataFlow::getNodeFromSharedSsa(post) and + origin = DataFlow::getNodeFromSharedSsa(read).(Node).getALocalSource() and + modeledPostUpdateValue(origin, DataFlow::TypeTracker::end()) + .flowsTo(DataFlow::getNodeFromSharedSsa(continuation)) and + // Resume after the operation without revisiting its argument or RHS reads. + Ssa2::localFlowStep(continuation.getSourceVariable(), continuation, successor, true) and + node2 = getSharedSsaFlowNode(successor) and not node1.getTopLevel().isExterns() ) - or - exists(Expr use | - node1 = TSsaUseNode(use) and - node2 = TValueNode(use) +} + +private predicate sharedSsaFlow(Node node1, Node node2) { + exists(Ssa2::Node ssaPred, Ssa2::Node ssaSucc, Ssa2::SsaConfig::SourceVariable variable | + Ssa2::localFlowStep(variable, ssaPred, ssaSucc, _) and + not variable.isCaptured() and + node1 = getSharedSsaFlowNode(ssaPred) and + node2 = getSharedSsaFlowNode(ssaSucc) and + node1 != node2 and + not node1.getTopLevel().isExterns() ) or - exists(ImplicitThisUse use | - node1 = TSsaUseNode(use) and - node2 = TImplicitThisUse(use, false) + // A barrier on one use must not sanitize the variable at subsequent uses. + exists(Ssa2::ExprNode read | + node1 = TSharedSsaReadNode(read) and + node2 = DataFlow::getNodeFromSharedSsa(read) and + not node1.getTopLevel().isExterns() ) + or + modeledPostUpdateFlow(node1, node2) } overlay[global] @@ -1278,8 +1328,6 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { nodeGetEnclosingCallable(pragma[only_bind_out](node1)) = nodeGetEnclosingCallable(pragma[only_bind_out](node2)) or - useUseFlow(node1, node2) - or exists(FlowSummaryImpl::Private::SummaryNode input, FlowSummaryImpl::Private::SummaryNode output | FlowSummaryPrivate::Steps::summaryStoreStep(input, MkAwaited(), output) and node1 = TFlowSummaryNode(input) and diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll index 7b479ac475b6..af4540dc1466 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll @@ -1,7 +1,11 @@ /** - * Instantiates the shared SSA library for JavaScript, but only to establish use-use flow. + * Instantiates the shared SSA library for JavaScript data flow. * - * JavaScript's old SSA library is still responsible for the ordinary SSA flow. + * Refinements are value-preserving uncertain writes, so shared SSA routes flow + * through refinements and their phi inputs. Phi definitions are retained to + * preserve the JavaScript SSA definition-node API. + * Synthetic reads at operation completion carry post-updates past argument + * and right-hand-side evaluation without changing the earlier expression values. */ overlay[local?] module; @@ -10,10 +14,97 @@ private import javascript as js private import codeql.ssa.Ssa private import semmle.javascript.internal.BasicBlockInternal as BasicBlockInternal private import semmle.javascript.dataflow.internal.VariableOrThis +private import semmle.javascript.dataflow.Refinements as Refinements + +private predicate captureAt(js::Cfg::BasicBlock bb, int i, SsaConfig::SourceVariable v) { + exists(js::LocalVariable local, js::StmtContainer container | + local = v.asLocalVariable() and + local.isCaptured() and + container = bb.getContainer() and + any(js::VarUse use | use.getVariable() = local).getContainer() = container + | + bb.getNode(i) instanceof js::ControlFlowEntryNode and + container != local.getDeclaringContainer() + or + bb.getNode(i) instanceof js::YieldExpr and + ( + container != local.getDeclaringContainer() or + local.getAnAccess().(js::LValue).getContainer() != local.getDeclaringContainer() + ) + or + bb.getNode(i) instanceof js::InvokeExpr and + local.getAnAccess().(js::LValue).getContainer() != local.getDeclaringContainer() + ) +} + +private predicate refinementAt(js::Cfg::BasicBlock bb, int i, SsaConfig::SourceVariable v) { + bb.getNode(i).(js::GuardControlFlowNode).getTest().(Refinements::Refinement).getRefinedVar() = + v.asLocalVariable() +} + +private predicate explicitVariableRead(js::ControlFlowNode read, SsaConfig::SourceVariable v) { + read.(js::VarUse).getVariable() = v.asLocalVariable() + or + read.(ThisUse).getBindingContainer() = v.asThisContainer() +} + +/** Gets an operation that may update the object evaluated at `read`. */ +private js::ControlFlowNode postUpdateOperation(js::ControlFlowNode read) { + exists(js::InvokeExpr call | read = call.getAnArgument() or read = call.getCallee() | + result = call + ) + or + exists(js::PropAccess access | read = access.getBase() | + result.(js::VarDef).getTarget() = access + or + not exists(js::VarDef definition | definition.getTarget() = access) and + result = access + or + access = any(js::CompoundAssignExpr assignment).getTarget() and + result = access + or + access = any(js::UpdateExpr update).getOperand().getUnderlyingReference() and + result = access + or + result.(js::MethodCallExpr).getCallee() = access + ) + or + result.(js::AwaitExpr).getOperand() = read + or + exists(js::Assignment assignment | + assignment.getTarget() instanceof js::PropAccess and + assignment.getRhs() = read and + result = assignment + ) + or + read instanceof ImplicitThisUse and + read instanceof js::FieldDefinition and + result = read +} + +// Continuations must not make otherwise dead variable definitions live. +bindingset[bb, i, v] +private predicate liveAfterOperation(js::Cfg::BasicBlock bb, int i, SsaConfig::SourceVariable v) { + exists(v.asThisContainer()) + or + exists(js::LocalVariable local | + local = v.asLocalVariable() and + ( + exists(int j | + j > i and + bb.useAt(j, local, _) and + not exists(int k | i < k and k < j | bb.defAt(k, local, _)) + ) + or + not exists(int k | k > i | bb.defAt(k, local, _)) and + bb.getASuccessor().localIsLiveAtEntry(local) + ) + ) +} module SsaConfig implements InputSig { class SourceVariable extends LocalVariableOrThis { - SourceVariable() { not this.isCaptured() } + SourceVariable() { exists(this.asLocalVariable()) or not this.isCaptured() } } pragma[nomagic] @@ -22,21 +113,50 @@ module SsaConfig implements InputSig { } predicate variableWrite(js::Cfg::BasicBlock bb, int i, SourceVariable v, boolean certain) { - certain = true and + bb instanceof js::ReachableBasicBlock and ( - bb.defAt(i, v.asLocalVariable(), _) + certain = true and + ( + bb.defAt(i, v.asLocalVariable(), _) + or + // Implicit initialization + bb = getEntryBlock(v.getDeclaringContainer().getFunctionBoundary()) and + i = -1 + or + captureAt(bb, i, v) + ) or - // Implicit initialization and function parameters - bb = getEntryBlock(v.getDeclaringContainer()) and - i = -1 + // Refinements preserve the input value but introduce a new SSA definition. + certain = false and + refinementAt(bb, i, v) ) } predicate variableRead(js::Cfg::BasicBlock bb, int i, SourceVariable v, boolean certain) { - bb.useAt(i, v.asLocalVariable(), _) and certain = true - or - certain = true and - bb.getNode(i).(ThisUse).getBindingContainer() = v.asThisContainer() + bb instanceof js::ReachableBasicBlock and + ( + certain = true and + ( + explicitVariableRead(bb.getNode(i), v) + or + not v.isCaptured() and + liveAfterOperation(bb, i, v) and + exists(js::ControlFlowNode read | + explicitVariableRead(read, v) and + postUpdateOperation(read) = bb.getNode(i) + ) + ) + or + // Closures can observe captured writes without a subsequent local read. + certain = false and + v.asLocalVariable().isCaptured() and + ( + bb.defAt(i - 1, v.asLocalVariable(), _) + or + i = 0 and + bb = getEntryBlock(v.getDeclaringContainer().getFunctionBoundary()) + ) + ) } } @@ -46,14 +166,155 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig { private import codeql.util.Boolean class Expr extends js::ControlFlowNode { - Expr() { this = any(SsaConfig::SourceVariable v).getAUse() } + Expr() { + this = any(SsaConfig::SourceVariable v).getAUse() + or + exists(js::ControlFlowNode read | + explicitVariableRead(read, _) and + this = postUpdateOperation(read) + ) + } predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) { this = bb.getNode(i) } } predicate ssaDefHasSource(WriteDefinition def) { - // This library only handles use-use flow after a post-update, there are no definitions, only uses. - none() + exists(SsaConfig::SourceVariable v, js::Cfg::BasicBlock bb, int i | + def.definesAt(v, bb, i) and + ( + exists(js::VarDef write | + bb.defAt(i, v.asLocalVariable(), write) and + write.getTarget() instanceof js::VarRef and + exists(write.getSource()) + ) + or + i = -1 and exists(v.asThisContainer()) + ) + ) + } + + predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) { any() } + + predicate includePhiDefsInFlowStep() { any() } + + // Inferred values depend on this SSA graph, so branch feasibility must remain syntactic. + private predicate createsObject(js::Expr value) { + value.getUnderlyingValue() instanceof js::ObjectExpr or + value.getUnderlyingValue() instanceof js::ArrayExpr or + value.getUnderlyingValue() instanceof js::Function or + value.getUnderlyingValue() instanceof js::ClassDefinition or + value.getUnderlyingValue() instanceof js::RegExpLiteral or + value.getUnderlyingValue() instanceof js::NewExpr + } + + private predicate isKnownTruthy(js::Expr value) { + createsObject(value) + or + value.getUnderlyingValue().(js::BooleanLiteral).getBoolValue() = true + or + value.getUnderlyingValue().(js::NumberLiteral).getValue().toFloat() != 0 + or + value.getUnderlyingValue().(js::StringLiteral).getStringValue() != "" + } + + private predicate isKnownFalsy(js::Expr value) { + value.getUnderlyingValue() instanceof js::NullLiteral or + value.getUnderlyingValue() instanceof js::SyntacticConstants::UndefinedConstant or + value.getUnderlyingValue().(js::BooleanLiteral).getBoolValue() = false or + value.getUnderlyingValue().(js::NumberLiteral).getValue().toFloat() = 0 or + value.getUnderlyingValue().(js::StringLiteral).getStringValue() = "" + } + + /** Gets an expression supplying `value`, excluding tests and discarded operands. */ + private js::Expr getAValueInput(js::Expr value) { + result = value.getUnderlyingValue() + or + exists(js::ConditionalExpr conditional | conditional = value.getUnderlyingValue() | + not isKnownFalsy(conditional.getCondition()) and + result = getAValueInput(conditional.getConsequent()) + or + not isKnownTruthy(conditional.getCondition()) and + result = getAValueInput(conditional.getAlternate()) + ) + or + exists(js::LogicalOrExpr logical | logical = value.getUnderlyingValue() | + result = getAValueInput(logical.getLeftOperand()) + or + not isKnownTruthy(logical.getLeftOperand()) and + result = getAValueInput(logical.getRightOperand()) + ) + or + exists(js::NullishCoalescingExpr coalescing | coalescing = value.getUnderlyingValue() | + result = getAValueInput(coalescing.getLeftOperand()) + or + not createsObject(coalescing.getLeftOperand()) and + not coalescing.getLeftOperand().getUnderlyingValue() instanceof + js::SyntacticConstants::PrimitiveLiteralConstant and + result = getAValueInput(coalescing.getRightOperand()) + ) + or + exists(js::LogicalAndExpr logical | logical = value.getUnderlyingValue() | + not isKnownFalsy(logical.getLeftOperand()) and + result = getAValueInput(logical.getRightOperand()) + ) + } + + private predicate preservingInput(Definition after, Definition input) { + uncertainWriteDefinitionInput(after, input) + or + phiHasInputFromBlock(after, input, _) + or + exists( + SsaConfig::SourceVariable v, js::BasicBlock bb, int i, js::VarDef write, js::Expr read, + js::BasicBlock readBlock, int readIndex + | + after.definesAt(v, bb, i) and + bb.defAt(i, v.asLocalVariable(), write) and + write.getTarget() instanceof js::VarRef and + read = getAValueInput(write.getSource()) and + read = readBlock.getNode(readIndex) and + explicitVariableRead(read, input.getSourceVariable()) and + ssaDefReachesRead(input.getSourceVariable(), input, readBlock, readIndex) + ) + } + + /** Holds if `after` can still refer to the object represented by `before`. */ + private predicate preservesDefinition(Definition before, Definition after) { + before = after + or + exists(Definition input | + preservingInput(after, input) and + preservesDefinition(before, input) + ) + } + + predicate postUpdateCfgNode(Expr read, js::Cfg::BasicBlock bb, int i) { + postUpdateOperation(read) = bb.getNode(i) and + exists( + SsaConfig::SourceVariable v, Definition before, Definition after, js::BasicBlock readBlock, + int readIndex + | + explicitVariableRead(read, v) and + read = readBlock.getNode(readIndex) and + ssaDefReachesRead(v, before, readBlock, readIndex) and + SsaConfig::variableRead(bb, i, v, true) and + ssaDefReachesRead(v, after, bb, i) and + // A later argument may have reassigned the variable to a different object. + preservesDefinition(before, after) + ) + } + + /** + * Holds if early SSA did not establish preservation and global flow should + * consult its modeled value-flow steps. + */ + additional predicate additionalPostUpdateCfgNode(Expr read, js::Cfg::BasicBlock bb, int i) { + postUpdateOperation(read) = bb.getNode(i) and + not postUpdateCfgNode(read, bb, i) and + exists(SsaConfig::SourceVariable v | + explicitVariableRead(read, v) and + ssaDefReachesRead(v, _, bb, i) + ) } cached @@ -108,3 +369,38 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig { } import DataFlowIntegration + +/** Holds if `definition` represents a conservative capture or recapture. */ +predicate isCaptureDefinition(Definition definition) { + exists(SsaConfig::SourceVariable variable, js::Cfg::BasicBlock bb, int i | + definition.definesAt(variable, bb, i) and + captureAt(bb, i, variable) + ) +} + +/** Holds if `definition` represents a value-preserving refinement. */ +predicate isRefinementDefinition(Definition definition) { + definition instanceof UncertainWriteDefinition +} + +/** Holds if `read` is an original variable or `this` read, not a continuation reference. */ +predicate isExplicitRead(SsaDataflowInput::Expr read) { explicitVariableRead(read, _) } + +/** Holds if `read` is a synthetic continuation at a potentially mutating operation. */ +predicate isPostUpdateRead(ExprNode read) { + not explicitVariableRead(read.getExpr(), read.getSourceVariable()) +} + +/** + * Holds if `continuation` follows an operation using `read`, but early SSA did + * not connect the post-update to that continuation's subsequent references. + */ +predicate additionalPostUpdateContinuation(ExprNode read, ExprNode continuation) { + explicitVariableRead(read.getExpr(), read.getSourceVariable()) and + continuation.getExpr() = postUpdateOperation(read.getExpr()) and + isPostUpdateRead(continuation) and + exists(js::Cfg::BasicBlock bb, int i | + continuation.(ReadNode).readsAt(bb, i, read.getSourceVariable()) and + SsaDataflowInput::additionalPostUpdateCfgNode(read.getExpr(), bb, i) + ) +} diff --git a/javascript/ql/src/NodeJS/InvalidExport.ql b/javascript/ql/src/NodeJS/InvalidExport.ql index 95d945bc0483..435e54484885 100644 --- a/javascript/ql/src/NodeJS/InvalidExport.ql +++ b/javascript/ql/src/NodeJS/InvalidExport.ql @@ -43,6 +43,8 @@ from Assignment assgn, Variable exportsVar, DataFlow::Node exportsVal where exportsAssign(assgn, exportsVar, exportsVal) and not exists(exportsVal.getAPredecessor()) and + // Post-updates change object contents, not the identity of the exported value. + not exportsVal instanceof DataFlow::PostUpdateNode and // this is OK if `exportsVal` flows into `module.exports` not moduleExportsAssign(_, exportsVal) and // export assignments do work in closure modules diff --git a/javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js b/javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js index 07e217ad4849..fe8d36bdab89 100644 --- a/javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js +++ b/javascript/ql/test/library-tests/BarrierGuardPhiInputs/tst.js @@ -3,7 +3,7 @@ function overwriteOnFailure() { if (!BARRIER(x)) { x = "safe"; } - SINK(x); // $ SPURIOUS: flow=overwrite + SINK(x); } function explicitElse() { @@ -13,7 +13,7 @@ function explicitElse() { } else { x = "safe"; } - SINK(x); // $ SPURIOUS: flow=else + SINK(x); } function preserveUnguardedInput() { @@ -21,7 +21,7 @@ function preserveUnguardedInput() { if (!BARRIER(x)) { x = SOURCE("fallback"); } - SINK(x); // $ flow=fallback SPURIOUS: flow=guarded + SINK(x); // $ flow=fallback } function returnOnFailure() { diff --git a/javascript/ql/test/library-tests/CallGraphs/FullTest/tests.expected b/javascript/ql/test/library-tests/CallGraphs/FullTest/tests.expected index 1192c8ec8fb6..c43392498820 100644 --- a/javascript/ql/test/library-tests/CallGraphs/FullTest/tests.expected +++ b/javascript/ql/test/library-tests/CallGraphs/FullTest/tests.expected @@ -102,12 +102,14 @@ test_getAFunctionValue | protoclass.js:3:10:3:10 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} | | protoclass.js:4:3:4:11 | this.init | protoclass.js:7:20:11:1 | functio ... m();\\n} | | protoclass.js:7:1:7:1 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} | +| protoclass.js:7:1:7:11 | [ssa-synth-read] F | protoclass.js:3:1:5:1 | functio ... it();\\n} | | protoclass.js:7:1:7:16 | F.prototype.init | protoclass.js:7:20:11:1 | functio ... m();\\n} | | protoclass.js:7:1:11:1 | F.proto ... m();\\n} | protoclass.js:7:20:11:1 | functio ... m();\\n} | | protoclass.js:7:20:11:1 | functio ... m();\\n} | protoclass.js:7:20:11:1 | functio ... m();\\n} | | protoclass.js:8:3:8:13 | this.method | protoclass.js:13:22:13:34 | function() {} | | protoclass.js:9:11:9:21 | this.method | protoclass.js:13:22:13:34 | function() {} | | protoclass.js:13:1:13:1 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} | +| protoclass.js:13:1:13:11 | [ssa-synth-read] F | protoclass.js:3:1:5:1 | functio ... it();\\n} | | protoclass.js:13:1:13:18 | F.prototype.method | protoclass.js:13:22:13:34 | function() {} | | protoclass.js:13:1:13:34 | F.proto ... on() {} | protoclass.js:13:22:13:34 | function() {} | | protoclass.js:13:22:13:34 | function() {} | protoclass.js:13:22:13:34 | function() {} | diff --git a/javascript/ql/test/library-tests/DataFlow/tests.expected b/javascript/ql/test/library-tests/DataFlow/tests.expected index 7ba6cbb60f39..d5e5bcef5c9a 100644 --- a/javascript/ql/test/library-tests/DataFlow/tests.expected +++ b/javascript/ql/test/library-tests/DataFlow/tests.expected @@ -36,11 +36,13 @@ basicBlock | arguments.js:4:13:4:24 | alsoFirstArg | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:4:13:4:39 | alsoFir ... ents[0] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:4:28:4:36 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | +| arguments.js:4:28:4:39 | [ssa-synth-read] arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:4:28:4:39 | arguments[0] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:4:38:4:38 | 0 | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:5:13:5:21 | secondArg | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:5:13:5:36 | secondA ... ents[1] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:5:25:5:33 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | +| arguments.js:5:25:5:36 | [ssa-synth-read] arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:5:25:5:36 | arguments[1] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:5:35:5:35 | 1 | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | | arguments.js:6:13:6:16 | args | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } | @@ -171,6 +173,7 @@ basicBlock | tst2.ts:13:39:13:38 | (...arg ... rgs); } | tst2.ts:1:1:1:0 | entry node of | | tst2.ts:13:39:13:38 | ...args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | | tst2.ts:13:39:13:38 | [function self-reference] (...arg ... rgs); } | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | +| tst2.ts:13:39:13:38 | [ssa-synth-read] this | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | @@ -212,15 +215,18 @@ basicBlock | tst.js:10:1:10:1 | x | tst.js:1:1:1:0 | entry node of | | tst.js:10:1:10:4 | x, y | tst.js:1:1:1:0 | entry node of | | tst.js:10:4:10:4 | y | tst.js:1:1:1:0 | entry node of | +| tst.js:11:1:11:1 | [ssa-synth-read] y | tst.js:11:1:11:1 | guard: x is false | | tst.js:11:1:11:1 | x | tst.js:1:1:1:0 | entry node of | | tst.js:11:1:11:1 | x | tst.js:11:1:11:1 | guard: x is false | | tst.js:11:1:11:1 | x | tst.js:11:1:11:1 | guard: x is true | | tst.js:11:1:11:6 | x && y | tst.js:1:1:1:0 | entry node of | | tst.js:11:6:11:6 | y | tst.js:11:1:11:1 | guard: x is true | +| tst.js:12:1:12:1 | [ssa-synth-read] y | tst.js:12:1:12:1 | guard: x is true | | tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | guard: x is false | | tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | guard: x is true | | tst.js:12:1:12:1 | x | tst.js:12:1:12:7 | x \|\| y; | | tst.js:12:1:12:6 | x \|\| y | tst.js:12:1:12:7 | x \|\| y; | +| tst.js:12:1:12:7 | [ssa-synth-read] y | tst.js:12:1:12:7 | x \|\| y; | | tst.js:12:1:12:7 | x | tst.js:12:1:12:7 | x \|\| y; | | tst.js:12:6:12:6 | y | tst.js:12:1:12:1 | guard: x is false | | tst.js:13:1:13:1 | z | tst.js:13:1:13:6 | z = y; | @@ -230,6 +236,7 @@ basicBlock | tst.js:13:5:13:5 | y | tst.js:13:1:13:6 | z = y; | | tst.js:14:1:14:1 | z | tst.js:13:1:13:6 | z = y; | | tst.js:14:1:14:9 | z ? x : y | tst.js:13:1:13:6 | z = y; | +| tst.js:14:5:14:5 | [ssa-synth-read] y | tst.js:14:1:14:1 | guard: z is true | | tst.js:14:5:14:5 | x | tst.js:14:1:14:1 | guard: z is true | | tst.js:14:9:14:9 | y | tst.js:14:1:14:1 | guard: z is false | | tst.js:16:1:20:2 | (functi ... "";\\n}) | tst.js:16:1:20:10 | (functi ... "arg"); | @@ -286,6 +293,7 @@ basicBlock | tst.js:32:12:32:12 | b | tst.js:32:1:32:0 | entry node of functio ... ables\\n} | | tst.js:33:10:33:10 | x | tst.js:32:1:32:0 | entry node of functio ... ables\\n} | | tst.js:35:1:35:1 | g | tst.js:16:1:20:10 | (functi ... "arg"); | +| tst.js:35:1:35:7 | [ssa-synth-read] g | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:35:1:35:7 | exceptional return of g(true) | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:35:1:35:7 | g(true) | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:35:3:35:6 | true | tst.js:16:1:20:10 | (functi ... "arg"); | @@ -307,10 +315,13 @@ basicBlock | tst.js:39:4:41:3 | return of method m | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } | | tst.js:40:5:40:8 | this | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } | | tst.js:43:1:43:1 | o | tst.js:16:1:20:10 | (functi ... "arg"); | +| tst.js:43:1:43:3 | [ssa-synth-read] o | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:43:1:43:3 | o.x | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:43:3:43:3 | x | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:44:1:44:1 | o | tst.js:16:1:20:10 | (functi ... "arg"); | +| tst.js:44:1:44:3 | [ssa-synth-read] o | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:44:1:44:3 | o.m | tst.js:16:1:20:10 | (functi ... "arg"); | +| tst.js:44:1:44:5 | [ssa-synth-read] o | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:44:1:44:5 | exceptional return of o.m() | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:44:1:44:5 | o.m() | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:44:3:44:3 | m | tst.js:16:1:20:10 | (functi ... "arg"); | @@ -331,6 +342,7 @@ basicBlock | tst.js:50:14:53:3 | exceptional return of constructor of class A | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | | tst.js:50:14:53:3 | return of constructor of class A | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | | tst.js:51:5:51:9 | super | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | +| tst.js:51:5:51:13 | [ssa-synth-read] this | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | | tst.js:51:5:51:13 | exceptional return of super(42) | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | | tst.js:51:5:51:13 | super(42) | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | | tst.js:51:11:51:12 | 42 | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | @@ -347,6 +359,7 @@ basicBlock | tst.js:60:1:60:1 | g | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:61:1:61:5 | ::o.m | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:61:3:61:3 | o | tst.js:16:1:20:10 | (functi ... "arg"); | +| tst.js:61:3:61:5 | [ssa-synth-read] o | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:61:3:61:5 | o.m | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:61:5:61:5 | m | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:62:1:62:1 | o | tst.js:16:1:20:10 | (functi ... "arg"); | @@ -947,8 +960,6 @@ enclosingExpr flowStep | arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:12:2 | (functi ... 3);\\n}) | | arguments.js:2:5:2:4 | arguments | arguments.js:4:28:4:36 | arguments | -| arguments.js:2:5:2:4 | arguments | arguments.js:5:25:5:33 | arguments | -| arguments.js:2:5:2:4 | arguments | arguments.js:6:20:6:28 | arguments | | arguments.js:2:5:10:5 | 'arguments' object of function f | arguments.js:4:28:4:36 | arguments | | arguments.js:2:5:10:5 | 'arguments' object of function f | arguments.js:5:25:5:33 | arguments | | arguments.js:2:5:10:5 | 'arguments' object of function f | arguments.js:6:20:6:28 | arguments | @@ -958,6 +969,12 @@ flowStep | arguments.js:2:14:2:14 | f | arguments.js:11:5:11:5 | f | | arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x | | arguments.js:2:16:2:16 | x | arguments.js:3:24:3:24 | x | +| arguments.js:4:28:4:36 | [post update] arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:4:28:4:36 | arguments | arguments.js:4:28:4:39 | [ssa-synth-read] arguments | +| arguments.js:4:28:4:39 | [ssa-synth-read] arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:5:25:5:33 | [post update] arguments | arguments.js:6:20:6:28 | arguments | +| arguments.js:5:25:5:33 | arguments | arguments.js:5:25:5:36 | [ssa-synth-read] arguments | +| arguments.js:5:25:5:36 | [ssa-synth-read] arguments | arguments.js:6:20:6:28 | arguments | | arguments.js:6:13:6:16 | args | arguments.js:7:24:7:27 | args | | arguments.js:6:20:6:28 | arguments | arguments.js:6:13:6:16 | args | | arguments.js:8:9:8:17 | arguments | arguments.js:9:27:9:35 | arguments | @@ -978,8 +995,8 @@ flowStep | sources.js:5:4:5:5 | 23 | sources.js:3:11:3:11 | x | | sources.js:9:14:9:18 | array | sources.js:9:14:9:18 | array | | sources.js:9:14:9:18 | array | sources.js:10:19:10:23 | array | -| sources.js:9:14:9:18 | array | sources.js:11:23:11:27 | array | | sources.js:10:12:10:14 | key | sources.js:10:28:10:30 | key | +| sources.js:10:19:10:23 | array | sources.js:11:23:11:27 | array | | sources.js:11:14:11:16 | key | sources.js:11:14:11:16 | key | | sources.js:11:14:11:16 | key | sources.js:11:32:11:34 | key | | tst2.ts:1:1:1:0 | A | tst2.ts:1:18:1:18 | A | @@ -999,12 +1016,12 @@ flowStep | tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | +| tst2.ts:13:39:13:38 | implicit 'this' | tst2.ts:13:39:13:38 | [ssa-synth-read] this | | tst2.ts:13:39:13:38 | this | tst2.ts:13:39:13:38 | implicit 'this' | | tst2.ts:15:11:15:13 | A.x | tst2.ts:15:11:15:30 | A.x satisfies number | | tst.js:1:1:1:0 | x | tst.js:3:5:3:5 | x | | tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | | tst.js:1:10:1:11 | fs | tst.js:7:1:7:2 | fs | -| tst.js:1:10:1:11 | fs | tst.js:22:24:22:25 | fs | | tst.js:3:5:3:5 | x | tst.js:3:5:3:5 | x | | tst.js:3:5:3:5 | x | tst.js:8:1:8:1 | x | | tst.js:3:5:3:5 | x | tst.js:9:2:9:2 | x | @@ -1016,31 +1033,39 @@ flowStep | tst.js:3:5:3:5 | x | tst.js:32:1:32:0 | x | | tst.js:3:9:3:10 | 42 | tst.js:3:5:3:5 | x | | tst.js:4:5:4:5 | y | tst.js:10:4:10:4 | y | -| tst.js:4:5:4:5 | y | tst.js:11:6:11:6 | y | -| tst.js:4:5:4:5 | y | tst.js:12:6:12:6 | y | -| tst.js:4:5:4:5 | y | tst.js:13:5:13:5 | y | -| tst.js:4:5:4:5 | y | tst.js:14:9:14:9 | y | -| tst.js:4:5:4:5 | y | tst.js:105:6:105:6 | y | | tst.js:4:9:4:12 | "hi" | tst.js:4:5:4:5 | y | +| tst.js:7:1:7:2 | fs | tst.js:22:24:22:25 | fs | | tst.js:9:2:9:2 | x | tst.js:9:1:9:3 | (x) | | tst.js:10:4:10:4 | y | tst.js:10:1:10:4 | x, y | +| tst.js:10:4:10:4 | y | tst.js:11:1:11:1 | [ssa-synth-read] y | +| tst.js:10:4:10:4 | y | tst.js:11:6:11:6 | y | +| tst.js:11:1:11:1 | [ssa-synth-read] y | tst.js:12:1:12:7 | [ssa-synth-read] y | | tst.js:11:1:11:1 | x | tst.js:12:1:12:7 | x | | tst.js:11:1:11:1 | x | tst.js:12:1:12:7 | x | | tst.js:11:6:11:6 | y | tst.js:11:1:11:6 | x && y | +| tst.js:11:6:11:6 | y | tst.js:12:1:12:7 | [ssa-synth-read] y | +| tst.js:12:1:12:1 | [ssa-synth-read] y | tst.js:13:5:13:5 | y | | tst.js:12:1:12:1 | x | tst.js:12:1:12:6 | x \|\| y | | tst.js:12:1:12:1 | x | tst.js:13:1:13:6 | x | | tst.js:12:1:12:1 | x | tst.js:13:1:13:6 | x | +| tst.js:12:1:12:7 | [ssa-synth-read] y | tst.js:12:1:12:1 | [ssa-synth-read] y | +| tst.js:12:1:12:7 | [ssa-synth-read] y | tst.js:12:6:12:6 | y | | tst.js:12:1:12:7 | x | tst.js:12:1:12:1 | x | | tst.js:12:1:12:7 | x | tst.js:12:1:12:1 | x | | tst.js:12:1:12:7 | x | tst.js:12:1:12:1 | x | | tst.js:12:6:12:6 | y | tst.js:12:1:12:6 | x \|\| y | +| tst.js:12:6:12:6 | y | tst.js:13:5:13:5 | y | | tst.js:13:1:13:1 | z | tst.js:14:1:14:1 | z | | tst.js:13:1:13:6 | x | tst.js:14:5:14:5 | x | | tst.js:13:1:13:6 | x | tst.js:25:3:25:3 | x | | tst.js:13:5:13:5 | y | tst.js:13:1:13:1 | z | | tst.js:13:5:13:5 | y | tst.js:13:1:13:5 | z = y | +| tst.js:13:5:13:5 | y | tst.js:14:5:14:5 | [ssa-synth-read] y | +| tst.js:13:5:13:5 | y | tst.js:14:9:14:9 | y | +| tst.js:14:5:14:5 | [ssa-synth-read] y | tst.js:105:6:105:6 | y | | tst.js:14:5:14:5 | x | tst.js:14:1:14:9 | z ? x : y | | tst.js:14:9:14:9 | y | tst.js:14:1:14:9 | z ? x : y | +| tst.js:14:9:14:9 | y | tst.js:105:6:105:6 | y | | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:1:20:2 | (functi ... "";\\n}) | | tst.js:16:13:16:13 | a | tst.js:16:13:16:13 | a | | tst.js:16:13:16:13 | a | tst.js:18:12:18:12 | a | @@ -1064,40 +1089,51 @@ flowStep | tst.js:32:1:32:0 | x | tst.js:33:10:33:10 | x | | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:10:32:10 | g | | tst.js:32:10:32:10 | g | tst.js:35:1:35:1 | g | -| tst.js:32:10:32:10 | g | tst.js:60:1:60:1 | g | -| tst.js:32:10:32:10 | g | tst.js:62:4:62:4 | g | | tst.js:33:10:33:10 | x | tst.js:32:1:34:1 | return of function g | +| tst.js:35:1:35:1 | [post update] g | tst.js:60:1:60:1 | g | +| tst.js:35:1:35:1 | g | tst.js:35:1:35:7 | [ssa-synth-read] g | +| tst.js:35:1:35:7 | [ssa-synth-read] g | tst.js:60:1:60:1 | g | | tst.js:37:5:37:5 | o | tst.js:43:1:43:1 | o | -| tst.js:37:5:37:5 | o | tst.js:44:1:44:1 | o | -| tst.js:37:5:37:5 | o | tst.js:61:3:61:3 | o | -| tst.js:37:5:37:5 | o | tst.js:62:1:62:1 | o | -| tst.js:37:5:37:5 | o | tst.js:77:15:77:15 | o | -| tst.js:37:5:37:5 | o | tst.js:80:15:80:15 | o | -| tst.js:37:5:37:5 | o | tst.js:83:23:83:23 | o | -| tst.js:37:5:37:5 | o | tst.js:85:23:85:23 | o | | tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} | tst.js:37:5:37:5 | o | | tst.js:39:4:39:3 | this | tst.js:40:5:40:8 | this | +| tst.js:43:1:43:1 | [post update] o | tst.js:44:1:44:1 | o | +| tst.js:43:1:43:1 | o | tst.js:43:1:43:3 | [ssa-synth-read] o | +| tst.js:43:1:43:3 | [ssa-synth-read] o | tst.js:44:1:44:1 | o | +| tst.js:44:1:44:1 | [post update] o | tst.js:44:1:44:5 | [ssa-synth-read] o | +| tst.js:44:1:44:1 | [post update] o | tst.js:61:3:61:3 | o | +| tst.js:44:1:44:1 | o | tst.js:44:1:44:3 | [ssa-synth-read] o | +| tst.js:44:1:44:3 | [ssa-synth-read] o | tst.js:44:1:44:5 | [ssa-synth-read] o | +| tst.js:44:1:44:5 | [ssa-synth-read] o | tst.js:61:3:61:3 | o | | tst.js:46:10:46:11 | "" | tst.js:46:1:46:11 | global = "" | | tst.js:49:1:54:1 | class A ... `\\n }\\n} | tst.js:49:7:49:7 | A | | tst.js:49:7:49:7 | A | tst.js:55:1:55:1 | A | | tst.js:50:14:50:13 | this | tst.js:51:5:51:9 | implicit 'this' | +| tst.js:51:5:51:9 | implicit 'this' | tst.js:51:5:51:13 | [ssa-synth-read] this | +| tst.js:60:1:60:1 | g | tst.js:62:4:62:4 | g | +| tst.js:61:3:61:3 | [post update] o | tst.js:62:1:62:1 | o | +| tst.js:61:3:61:3 | o | tst.js:61:3:61:5 | [ssa-synth-read] o | +| tst.js:61:3:61:5 | [ssa-synth-read] o | tst.js:62:1:62:1 | o | +| tst.js:62:1:62:1 | o | tst.js:77:15:77:15 | o | | tst.js:64:1:67:1 | functio ... lysed\\n} | tst.js:64:11:64:11 | h | | tst.js:64:11:64:11 | h | tst.js:68:12:68:12 | h | | tst.js:68:5:68:8 | iter | tst.js:69:1:69:4 | iter | | tst.js:68:12:68:14 | h() | tst.js:68:5:68:8 | iter | | tst.js:77:10:77:10 | i | tst.js:78:3:78:3 | i | +| tst.js:77:15:77:15 | o | tst.js:80:15:80:15 | o | | tst.js:80:10:80:10 | v | tst.js:81:3:81:3 | v | +| tst.js:80:15:80:15 | o | tst.js:83:23:83:23 | o | | tst.js:83:18:83:18 | v | tst.js:83:26:83:26 | v | +| tst.js:83:23:83:23 | o | tst.js:85:23:85:23 | o | | tst.js:85:18:85:18 | v | tst.js:85:26:85:26 | v | | tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:87:1:92:2 | (functi ... + z;\\n}) | | tst.js:87:13:87:16 | p: x | tst.js:87:16:87:16 | x | | tst.js:87:16:87:16 | x | tst.js:91:10:91:10 | x | | tst.js:87:22:87:22 | ...o | tst.js:87:22:87:22 | o | | tst.js:87:22:87:22 | o | tst.js:88:18:88:18 | o | -| tst.js:87:22:87:22 | o | tst.js:90:15:90:15 | o | | tst.js:88:9:88:12 | q: y | tst.js:88:12:88:12 | y | | tst.js:88:12:88:12 | y | tst.js:91:14:91:14 | y | | tst.js:88:18:88:18 | o | tst.js:88:7:88:14 | { q: y } | +| tst.js:88:18:88:18 | o | tst.js:90:15:90:15 | o | | tst.js:90:4:90:15 | { r: z } = o | tst.js:90:3:90:16 | ({ r: z } = o) | | tst.js:90:6:90:9 | r: z | tst.js:90:9:90:9 | z | | tst.js:90:9:90:9 | z | tst.js:91:18:91:18 | z | @@ -1111,10 +1147,10 @@ flowStep | tst.js:98:13:98:13 | x | tst.js:102:10:102:10 | x | | tst.js:98:19:98:22 | ...rest | tst.js:98:19:98:22 | rest | | tst.js:98:19:98:22 | rest | tst.js:99:15:99:18 | rest | -| tst.js:98:19:98:22 | rest | tst.js:101:13:101:16 | rest | | tst.js:99:9:99:9 | y | tst.js:99:9:99:9 | y | | tst.js:99:9:99:9 | y | tst.js:102:14:102:14 | y | | tst.js:99:15:99:18 | rest | tst.js:99:7:99:11 | [ y ] | +| tst.js:99:15:99:18 | rest | tst.js:101:13:101:16 | rest | | tst.js:101:7:101:7 | z | tst.js:101:7:101:7 | z | | tst.js:101:7:101:7 | z | tst.js:102:18:102:18 | z | | tst.js:101:13:101:16 | rest | tst.js:101:3:101:9 | [ , z ] | @@ -1147,7 +1183,9 @@ flowStep getImmediatePredecessor | arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:12:2 | (functi ... 3);\\n}) | | arguments.js:2:5:2:4 | arguments | arguments.js:4:28:4:36 | arguments | +| arguments.js:2:5:2:4 | arguments | arguments.js:4:28:4:39 | [ssa-synth-read] arguments | | arguments.js:2:5:2:4 | arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:2:5:2:4 | arguments | arguments.js:5:25:5:36 | [ssa-synth-read] arguments | | arguments.js:2:5:2:4 | arguments | arguments.js:6:20:6:28 | arguments | | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:14:2:14 | f | | arguments.js:2:14:2:14 | f | arguments.js:11:5:11:5 | f | @@ -1189,6 +1227,7 @@ getImmediatePredecessor | tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | +| tst2.ts:13:39:13:38 | this | tst2.ts:13:39:13:38 | [ssa-synth-read] this | | tst2.ts:13:39:13:38 | this | tst2.ts:13:39:13:38 | implicit 'this' | | tst2.ts:15:11:15:13 | A.x | tst2.ts:15:11:15:30 | A.x satisfies number | | tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | @@ -1237,11 +1276,16 @@ getImmediatePredecessor | tst.js:32:1:32:0 | x | tst.js:33:10:33:10 | x | | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:10:32:10 | g | | tst.js:32:10:32:10 | g | tst.js:35:1:35:1 | g | +| tst.js:32:10:32:10 | g | tst.js:35:1:35:7 | [ssa-synth-read] g | | tst.js:32:10:32:10 | g | tst.js:60:1:60:1 | g | | tst.js:32:10:32:10 | g | tst.js:62:4:62:4 | g | | tst.js:37:5:37:5 | o | tst.js:43:1:43:1 | o | +| tst.js:37:5:37:5 | o | tst.js:43:1:43:3 | [ssa-synth-read] o | | tst.js:37:5:37:5 | o | tst.js:44:1:44:1 | o | +| tst.js:37:5:37:5 | o | tst.js:44:1:44:3 | [ssa-synth-read] o | +| tst.js:37:5:37:5 | o | tst.js:44:1:44:5 | [ssa-synth-read] o | | tst.js:37:5:37:5 | o | tst.js:61:3:61:3 | o | +| tst.js:37:5:37:5 | o | tst.js:61:3:61:5 | [ssa-synth-read] o | | tst.js:37:5:37:5 | o | tst.js:62:1:62:1 | o | | tst.js:37:5:37:5 | o | tst.js:77:15:77:15 | o | | tst.js:37:5:37:5 | o | tst.js:80:15:80:15 | o | @@ -1253,6 +1297,7 @@ getImmediatePredecessor | tst.js:49:1:54:1 | class A ... `\\n }\\n} | tst.js:49:7:49:7 | A | | tst.js:49:7:49:7 | A | tst.js:55:1:55:1 | A | | tst.js:50:14:50:13 | this | tst.js:51:5:51:9 | implicit 'this' | +| tst.js:50:14:50:13 | this | tst.js:51:5:51:13 | [ssa-synth-read] this | | tst.js:64:1:67:1 | functio ... lysed\\n} | tst.js:64:11:64:11 | h | | tst.js:64:11:64:11 | h | tst.js:68:12:68:12 | h | | tst.js:68:5:68:8 | iter | tst.js:69:1:69:4 | iter | diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected index c6ca30cd3292..c5c9b5fe8d73 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected @@ -13,6 +13,7 @@ test_getAReferenceTo | test.js:2:11:2:13 | foo | foo | | test.js:2:11:2:17 | foo.bar | foo.bar | | test.js:3:3:3:3 | v | foo.bar | +| test.js:3:3:3:7 | [ssa-synth-read] v | foo.bar | | test.js:3:3:3:7 | v.baz | foo.bar.baz | | test.js:4:7:4:24 | { baz, a, b: {c} } | foo.bar | | test.js:4:9:4:11 | baz | foo.bar.baz | diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js index 0018fbf34c12..d83e90bc64d5 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/captured.js @@ -96,7 +96,7 @@ function legacyGuardedPhi(condition) { } else { value = "safe"; } - SINK(value); // $ SPURIOUS: capturedFlow=legacy-guarded-phi + SINK(value); } function legacyGuardedWithReads(condition) { @@ -110,5 +110,5 @@ function legacyGuardedWithReads(condition) { value = "safe"; } } - SINK(value); // $ SPURIOUS: capturedFlow=legacy-with-guard + SINK(value); } diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected index 08ad3b0b1a14..1cbd6fd3eedf 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.expected @@ -1,502 +1,21 @@ nonUniqueDef readWithoutDef -| local.js:172:9:172:24 | liveBeforeReturn | local.js:174:3:174:27 | const d ... "dead"; | 10 | -| refinement.js:449:41:449:45 | value | refinement.js:450:98:450:102 | value | 0 | -| refinement.js:454:29:454:33 | value | refinement.js:455:82:455:86 | value | 0 | deadDef notDominatedByDef nonUniqueDefReachesEndOfBlock uselessPhiNode -| namespace.ts:6:3:8:3 | SSA phi(value) | 1 | readWithoutPriorRef -| local.js:172:9:172:24 | liveBeforeReturn | local.js:174:3:174:27 | const d ... "dead"; | 10 | -| refinement.js:449:41:449:45 | value | refinement.js:450:98:450:102 | value | 0 | -| refinement.js:454:29:454:33 | value | refinement.js:455:82:455:86 | value | 0 | readWithMultiplePriorRefs phiWithoutTwoPriorRefs -| namespace.ts:6:3:8:3 | SSA phi(value) | namespace.ts:6:3:8:3 | if (val ... ace\\n } | namespace.ts:2:7:2:11 | value | 1 | phiReadWithoutTwoPriorRefs ambiguousReadNode nonUniqueSsaDefinition nonUniqueSsaVariable missingSsaNodeMetadata -| captured.js:22:10:22:24 | [ssa-use] uncapturedWrite | -| captured.js:45:1:45:23 | [ssa-use] destruc ... aration | -| captured.js:53:1:53:22 | [ssa-use] destruc ... ignment | -| captured.js:59:1:59:21 | [ssa-use] destruc ... rameter | -| captured.js:67:1:67:16 | [ssa-use] destructuredLoop | -| captured.js:73:1:73:17 | [ssa-use] destructuredArray | -| captured.js:79:1:79:18 | [ssa-use] readTopLevelObject | -| captured.js:91:1:91:15 | [ssa-use] readTopLevelPhi | -| captured.js:95:7:95:15 | [ssa-use] condition | -| captured.js:95:28:95:32 | [ssa-use] value | -| captured.js:95:36:96:3 | [ssa-synth-read] value | -| captured.js:97:5:97:9 | [ssa-use] value | -| captured.js:99:8:99:12 | [ssa-use] value | -| captured.js:104:7:104:11 | [ssa-use] value | -| captured.js:106:9:106:17 | [ssa-use] condition | -| captured.js:107:20:107:24 | [ssa-use] value | -| captured.js:108:11:108:15 | [ssa-use] value | -| captured.js:110:7:110:11 | [ssa-use] value | -| captured.js:113:8:113:12 | [ssa-use] value | -| local.js:3:7:3:15 | [ssa-use] condition | -| local.js:4:5:4:9 | [ssa-use] value | -| local.js:6:5:6:9 | [ssa-use] value | -| local.js:8:7:8:20 | [ssa-use] otherCondition | -| local.js:9:10:9:14 | [ssa-use] value | -| local.js:11:9:11:13 | [ssa-use] value | -| local.js:16:8:16:12 | [ssa-use] value | -| local.js:17:3:17:7 | [ssa-use] value | -| local.js:18:8:18:12 | [ssa-use] value | -| local.js:22:3:22:7 | [ssa-use] value | -| local.js:22:52:22:56 | [ssa-use] value | -| local.js:23:8:23:12 | [ssa-use] value | -| local.js:27:29:27:33 | [ssa-use] value | -| local.js:27:41:27:45 | [ssa-use] value | -| local.js:28:8:28:12 | [ssa-use] value | -| local.js:32:40:32:44 | [ssa-use] value | -| local.js:32:53:32:57 | [ssa-use] value | -| local.js:36:39:36:43 | [ssa-use] value | -| local.js:36:46:36:50 | [ssa-use] value | -| local.js:37:8:37:12 | [ssa-use] value | -| local.js:41:39:41:43 | [ssa-use] value | -| local.js:41:46:41:50 | [ssa-use] value | -| local.js:41:54:41:58 | [ssa-use] value | -| local.js:42:8:42:12 | [ssa-use] value | -| local.js:46:3:46:7 | [ssa-use] value | -| local.js:46:21:46:25 | [ssa-use] value | -| local.js:46:29:46:33 | [ssa-use] value | -| local.js:47:8:47:12 | [ssa-use] value | -| local.js:51:37:51:41 | [ssa-use] value | -| local.js:51:44:51:48 | [ssa-use] value | -| local.js:51:52:51:60 | [ssa-use] condition | -| local.js:51:64:51:68 | [ssa-use] value | -| local.js:52:8:52:12 | [ssa-use] value | -| local.js:56:46:56:50 | [ssa-use] value | -| local.js:56:53:56:57 | [ssa-use] value | -| local.js:60:35:60:39 | [ssa-use] value | -| local.js:60:49:60:53 | [ssa-use] value | -| local.js:61:8:61:12 | [ssa-use] value | -| local.js:65:3:65:7 | [ssa-use] value | -| local.js:66:10:66:14 | [ssa-use] value | -| local.js:69:10:69:14 | [ssa-use] value | -| local.js:71:8:71:12 | [ssa-use] value | -| local.js:75:4:75:8 | [ssa-use] value | -| local.js:75:17:75:21 | [ssa-use] value | -| local.js:75:28:75:32 | [ssa-use] value | -| local.js:76:8:76:12 | [ssa-use] value | -| local.js:81:43:81:47 | [ssa-use] value | -| local.js:83:10:83:14 | [ssa-use] value | -| local.js:85:8:85:12 | [ssa-use] value | -| local.js:90:10:90:14 | [ssa-use] value | -| local.js:91:31:91:35 | [ssa-use] value | -| local.js:92:10:92:14 | [ssa-use] value | -| local.js:98:14:98:18 | [ssa-use] value | -| local.js:100:16:100:20 | [ssa-use] value | -| local.js:102:14:102:18 | [ssa-use] value | -| local.js:106:7:106:11 | [ssa-use] value | -| local.js:107:16:107:20 | [ssa-use] value | -| local.js:108:7:108:11 | [ssa-use] value | -| local.js:109:12:109:16 | [ssa-use] value | -| local.js:115:7:115:11 | [ssa-use] value | -| local.js:116:10:116:14 | [ssa-use] value | -| local.js:117:5:117:9 | [ssa-use] value | -| local.js:118:9:118:13 | [ssa-use] value | -| local.js:119:10:119:14 | [ssa-use] value | -| local.js:124:7:124:31 | [ssa-synth-read] value | -| local.js:124:14:124:18 | [ssa-use] value | -| local.js:124:36:124:62 | [ssa-synth-read] value | -| local.js:124:43:124:47 | [ssa-use] value | -| local.js:125:10:125:14 | [ssa-use] value | -| local.js:126:5:126:9 | [ssa-use] value | -| local.js:127:9:127:13 | [ssa-use] value | -| local.js:128:10:128:14 | [ssa-use] value | -| local.js:133:7:133:11 | [ssa-use] value | -| local.js:134:5:134:9 | [ssa-use] value | -| local.js:135:16:135:20 | [ssa-use] value | -| local.js:136:12:136:16 | [ssa-use] value | -| local.js:142:7:142:11 | [ssa-synth-read] value | -| local.js:142:7:142:11 | [ssa-use] value | -| local.js:143:5:143:9 | [ssa-use] value | -| local.js:144:9:144:13 | [ssa-use] value | -| local.js:146:8:146:12 | [ssa-use] value | -| local.js:150:3:150:7 | [ssa-use] value | -| local.js:151:8:151:12 | [ssa-use] value | -| local.js:166:49:166:54 | [ssa-use] second | -| local.js:167:8:167:12 | [ssa-use] first | -| local.js:168:8:168:13 | [ssa-use] second | -| local.js:173:10:173:25 | [ssa-use] liveBeforeReturn | -| local.js:175:7:175:15 | [ssa-use] deadLocal | -| local.js:176:7:176:22 | [ssa-use] liveBeforeReturn | -| local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | -| local.js:182:11:182:14 | [ssa-use] this | -| local.js:185:9:185:17 | [ssa-use] condition | -| local.js:186:7:186:11 | [ssa-use] super | -| local.js:188:7:188:11 | [ssa-use] super | -| local.js:190:9:190:12 | [ssa-use] this | -| namespace.ts:4:5:4:9 | [ssa-use] value | -| namespace.ts:6:7:6:11 | [ssa-use] value | -| namespace.ts:7:10:7:14 | [ssa-use] value | -| nodes.js:3:7:3:15 | [ssa-use] condition | -| nodes.js:4:5:4:9 | [ssa-use] value | -| nodes.js:6:5:6:9 | [ssa-use] value | -| nodes.js:8:7:8:20 | [ssa-use] otherCondition | -| nodes.js:9:11:9:15 | [ssa-use] value | -| nodes.js:11:9:11:13 | [ssa-use] value | -| nodes.js:16:7:16:11 | [ssa-synth-read] value | -| nodes.js:16:7:16:11 | [ssa-use] value | -| nodes.js:17:5:17:9 | [ssa-use] value | -| nodes.js:19:7:19:15 | [ssa-use] condition | -| nodes.js:20:11:20:15 | [ssa-use] value | -| nodes.js:22:9:22:13 | [ssa-use] value | -| nodes.js:28:7:28:20 | [ssa-use] firstCondition | -| nodes.js:29:9:29:23 | [ssa-use] secondCondition | -| nodes.js:30:7:30:11 | [ssa-use] value | -| nodes.js:32:7:32:11 | [ssa-use] value | -| nodes.js:36:5:36:9 | [ssa-use] value | -| nodes.js:38:7:38:20 | [ssa-use] thirdCondition | -| nodes.js:39:11:39:15 | [ssa-use] value | -| nodes.js:41:9:41:13 | [ssa-use] value | -| nodes.js:47:7:47:15 | [ssa-use] condition | -| nodes.js:55:3:55:9 | [ssa-use] capture | -| nodes.js:56:7:56:20 | [ssa-use] otherCondition | -| nodes.js:64:16:64:24 | [ssa-use] parameter | -| nodes.js:66:16:66:28 | [ssa-use] uninitialized | -| nodes.js:67:30:67:38 | [ssa-use] parameter | -| nodes.js:68:16:68:20 | [ssa-use] value | -| nodes.js:69:14:69:18 | [ssa-use] value | -| nodes.js:70:18:70:22 | [ssa-use] value | -| nodes.js:85:3:85:7 | [ssa-use] write | -| nodes.js:87:10:87:13 | [ssa-use] read | -| refinement.js:3:8:3:30 | [ssa-use] refinem ... rSource | -| refinement.js:4:10:4:32 | [ssa-use] refinem ... rSource | -| refinement.js:10:16:10:21 | [ssa-use] object | -| refinement.js:10:23:10:25 | [ssa-use] key | -| refinement.js:11:8:11:13 | [ssa-use] object | -| refinement.js:11:15:11:17 | [ssa-use] key | -| refinement.js:12:8:12:13 | [ssa-use] object | -| refinement.js:13:3:13:5 | [ssa-use] key | -| refinement.js:14:8:14:13 | [ssa-use] object | -| refinement.js:14:15:14:17 | [ssa-use] key | -| refinement.js:19:7:19:19 | [ssa-use] phiReadSource | -| refinement.js:20:9:20:17 | [ssa-use] condition | -| refinement.js:21:12:21:33 | [ssa-synth-read] phiReadSource | -| refinement.js:21:20:21:32 | [ssa-use] phiReadSource | -| refinement.js:23:12:23:33 | [ssa-synth-read] phiReadSource | -| refinement.js:23:20:23:32 | [ssa-use] phiReadSource | -| refinement.js:25:10:25:22 | [ssa-use] phiReadSource | -| refinement.js:31:8:31:26 | [ssa-use] refinementPhiSource | -| refinement.js:32:9:32:17 | [ssa-synth-read] refinementPhiSource | -| refinement.js:32:9:32:17 | [ssa-use] condition | -| refinement.js:33:7:33:25 | [ssa-use] refinementPhiSource | -| refinement.js:35:10:35:28 | [ssa-use] refinementPhiSource | -| refinement.js:41:7:41:11 | [ssa-use] value | -| refinement.js:41:7:41:19 | [ssa-synth-read] value | -| refinement.js:41:24:41:28 | [ssa-use] value | -| refinement.js:41:24:41:36 | [ssa-synth-read] value | -| refinement.js:42:10:42:14 | [ssa-use] value | -| refinement.js:48:7:48:11 | [ssa-use] value | -| refinement.js:48:7:48:19 | [ssa-synth-read] value | -| refinement.js:48:24:48:28 | [ssa-use] value | -| refinement.js:48:24:48:36 | [ssa-synth-read] value | -| refinement.js:48:39:55:3 | [ssa-synth-read] value | -| refinement.js:49:9:49:17 | [ssa-use] condition | -| refinement.js:50:11:50:15 | [ssa-use] value | -| refinement.js:52:11:52:15 | [ssa-use] value | -| refinement.js:54:10:54:14 | [ssa-use] value | -| refinement.js:59:7:59:11 | [ssa-synth-read] value | -| refinement.js:59:7:59:11 | [ssa-use] value | -| refinement.js:60:5:60:9 | [ssa-use] value | -| refinement.js:62:8:62:12 | [ssa-use] value | -| refinement.js:66:8:66:12 | [ssa-use] value | -| refinement.js:67:9:67:17 | [ssa-synth-read] value | -| refinement.js:67:9:67:17 | [ssa-use] condition | -| refinement.js:68:7:68:11 | [ssa-use] value | -| refinement.js:70:10:70:14 | [ssa-use] value | -| refinement.js:75:7:75:11 | [ssa-synth-read] value | -| refinement.js:75:7:75:11 | [ssa-use] value | -| refinement.js:76:5:76:9 | [ssa-use] value | -| refinement.js:78:7:78:15 | [ssa-use] condition | -| refinement.js:79:5:79:9 | [ssa-use] value | -| refinement.js:81:8:81:12 | [ssa-use] value | -| refinement.js:85:7:85:11 | [ssa-synth-read] value | -| refinement.js:85:7:85:11 | [ssa-use] value | -| refinement.js:86:5:86:9 | [ssa-use] value | -| refinement.js:88:7:88:15 | [ssa-use] condition | -| refinement.js:89:9:89:13 | [ssa-use] value | -| refinement.js:91:9:91:13 | [ssa-use] value | -| refinement.js:93:8:93:12 | [ssa-use] value | -| refinement.js:98:8:98:12 | [ssa-use] value | -| refinement.js:99:9:99:17 | [ssa-synth-read] value | -| refinement.js:99:9:99:17 | [ssa-use] condition | -| refinement.js:100:7:100:11 | [ssa-use] value | -| refinement.js:102:9:102:22 | [ssa-use] otherCondition | -| refinement.js:103:12:103:16 | [ssa-use] value | -| refinement.js:105:12:105:16 | [ssa-use] value | -| refinement.js:111:9:111:13 | [ssa-use] value | -| refinement.js:112:10:112:14 | [ssa-use] value | -| refinement.js:117:9:117:22 | [ssa-use] firstCondition | -| refinement.js:118:11:118:25 | [ssa-use] secondCondition | -| refinement.js:119:9:119:13 | [ssa-use] value | -| refinement.js:121:9:121:13 | [ssa-use] value | -| refinement.js:125:7:125:11 | [ssa-use] value | -| refinement.js:127:10:127:14 | [ssa-use] value | -| refinement.js:132:9:132:22 | [ssa-use] firstCondition | -| refinement.js:133:11:133:25 | [ssa-use] secondCondition | -| refinement.js:134:9:134:13 | [ssa-use] value | -| refinement.js:136:9:136:13 | [ssa-use] value | -| refinement.js:140:7:140:11 | [ssa-use] value | -| refinement.js:142:9:142:22 | [ssa-use] thirdCondition | -| refinement.js:143:12:143:16 | [ssa-use] value | -| refinement.js:145:11:145:15 | [ssa-use] value | -| refinement.js:151:9:151:13 | [ssa-use] value | -| refinement.js:152:11:152:19 | [ssa-use] condition | -| refinement.js:153:14:153:27 | [ssa-synth-read] value | -| refinement.js:153:22:153:26 | [ssa-use] value | -| refinement.js:155:14:155:27 | [ssa-synth-read] value | -| refinement.js:155:22:155:26 | [ssa-use] value | -| refinement.js:157:18:157:22 | [ssa-use] value | -| refinement.js:158:14:158:18 | [ssa-use] value | -| refinement.js:165:10:165:14 | [ssa-use] value | -| refinement.js:166:11:166:19 | [ssa-synth-read] value | -| refinement.js:166:11:166:19 | [ssa-use] condition | -| refinement.js:167:13:167:17 | [ssa-use] value | -| refinement.js:169:12:169:16 | [ssa-use] value | -| refinement.js:175:9:175:17 | [ssa-use] condition | -| refinement.js:175:20:176:5 | [ssa-synth-read] value | -| refinement.js:176:16:176:20 | [ssa-synth-read] value | -| refinement.js:176:16:176:20 | [ssa-use] value | -| refinement.js:177:7:177:11 | [ssa-use] value | -| refinement.js:179:9:179:22 | [ssa-use] otherCondition | -| refinement.js:180:12:180:16 | [ssa-use] value | -| refinement.js:182:11:182:15 | [ssa-use] value | -| refinement.js:188:18:188:22 | [ssa-use] value | -| refinement.js:189:10:189:14 | [ssa-use] value | -| refinement.js:194:28:194:32 | [ssa-use] value | -| refinement.js:195:10:195:14 | [ssa-use] value | -| refinement.js:200:9:200:17 | [ssa-use] condition | -| refinement.js:201:20:201:24 | [ssa-use] value | -| refinement.js:203:20:203:24 | [ssa-use] value | -| refinement.js:205:10:205:14 | [ssa-use] value | -| refinement.js:210:17:210:21 | [ssa-use] value | -| refinement.js:211:10:211:14 | [ssa-use] value | -| refinement.js:216:24:216:28 | [ssa-use] value | -| refinement.js:217:9:217:10 | [ssa-use] ok | -| refinement.js:218:11:218:15 | [ssa-use] value | -| refinement.js:220:7:220:11 | [ssa-use] value | -| refinement.js:222:10:222:14 | [ssa-use] value | -| refinement.js:227:24:227:28 | [ssa-use] value | -| refinement.js:228:9:228:10 | [ssa-use] ok | -| refinement.js:228:13:229:5 | [ssa-synth-read] value | -| refinement.js:230:7:230:11 | [ssa-use] value | -| refinement.js:232:10:232:14 | [ssa-use] value | -| refinement.js:237:24:237:28 | [ssa-use] value | -| refinement.js:238:16:238:20 | [ssa-use] value | -| refinement.js:239:11:239:12 | [ssa-use] ok | -| refinement.js:239:15:240:7 | [ssa-synth-read] value | -| refinement.js:241:9:241:13 | [ssa-use] value | -| refinement.js:243:12:243:16 | [ssa-use] value | -| refinement.js:249:11:249:21 | [ssa-use] scopeObject | -| refinement.js:250:19:250:23 | [ssa-use] value | -| refinement.js:251:13:251:17 | [ssa-use] value | -| refinement.js:253:9:253:13 | [ssa-use] value | -| refinement.js:256:10:256:14 | [ssa-use] value | -| refinement.js:260:5:260:10 | [ssa-use] target | -| refinement.js:260:23:260:29 | [ssa-use] payload | -| refinement.js:264:29:264:33 | [ssa-use] value | -| refinement.js:264:70:264:74 | [ssa-use] value | -| refinement.js:264:78:264:82 | [ssa-use] value | -| refinement.js:265:10:265:14 | [ssa-use] value | -| refinement.js:269:29:269:33 | [ssa-use] value | -| refinement.js:269:37:269:41 | [ssa-use] value | -| refinement.js:269:53:269:57 | [ssa-use] value | -| refinement.js:270:10:270:14 | [ssa-use] value | -| refinement.js:274:5:274:9 | [ssa-use] value | -| refinement.js:274:23:274:27 | [ssa-use] value | -| refinement.js:274:31:274:35 | [ssa-use] value | -| refinement.js:275:10:275:14 | [ssa-use] value | -| refinement.js:279:19:279:23 | [ssa-use] value | -| refinement.js:280:29:280:33 | [ssa-use] value | -| refinement.js:280:63:280:67 | [ssa-use] value | -| refinement.js:280:71:280:75 | [ssa-use] alias | -| refinement.js:281:10:281:14 | [ssa-use] value | -| refinement.js:285:29:285:33 | [ssa-use] value | -| refinement.js:285:73:285:77 | [ssa-use] value | -| refinement.js:285:81:285:89 | [ssa-use] condition | -| refinement.js:285:93:285:97 | [ssa-use] value | -| refinement.js:286:10:286:14 | [ssa-use] value | -| refinement.js:290:29:290:33 | [ssa-use] value | -| refinement.js:290:69:290:73 | [ssa-use] value | -| refinement.js:290:77:290:85 | [ssa-use] condition | -| refinement.js:290:89:290:93 | [ssa-use] value | -| refinement.js:290:97:290:101 | [ssa-use] value | -| refinement.js:291:10:291:14 | [ssa-use] value | -| refinement.js:295:29:295:33 | [ssa-use] value | -| refinement.js:295:72:295:76 | [ssa-use] value | -| refinement.js:295:80:295:84 | [ssa-use] value | -| refinement.js:296:10:296:14 | [ssa-use] value | -| refinement.js:300:29:300:33 | [ssa-use] value | -| refinement.js:300:72:300:76 | [ssa-use] value | -| refinement.js:300:80:300:84 | [ssa-use] value | -| refinement.js:301:10:301:14 | [ssa-use] value | -| refinement.js:305:29:305:33 | [ssa-use] value | -| refinement.js:305:68:305:72 | [ssa-use] value | -| refinement.js:305:76:305:84 | [ssa-use] condition | -| refinement.js:305:89:305:93 | [ssa-use] value | -| refinement.js:306:10:306:14 | [ssa-use] value | -| refinement.js:310:29:310:33 | [ssa-use] value | -| refinement.js:310:70:310:74 | [ssa-use] value | -| refinement.js:310:78:310:86 | [ssa-use] condition | -| refinement.js:310:98:310:102 | [ssa-use] value | -| refinement.js:310:107:310:111 | [ssa-use] value | -| refinement.js:311:10:311:14 | [ssa-use] value | -| refinement.js:315:19:315:27 | [ssa-use] condition | -| refinement.js:315:31:315:35 | [ssa-use] value | -| refinement.js:315:39:315:40 | [ssa-synth-read] value | -| refinement.js:316:29:316:33 | [ssa-use] value | -| refinement.js:316:74:316:78 | [ssa-use] value | -| refinement.js:316:82:316:86 | [ssa-use] alias | -| refinement.js:317:10:317:14 | [ssa-use] value | -| refinement.js:321:5:321:9 | [ssa-use] value | -| refinement.js:321:23:321:27 | [ssa-use] value | -| refinement.js:321:31:321:39 | [ssa-use] condition | -| refinement.js:321:43:321:47 | [ssa-use] value | -| refinement.js:322:10:322:14 | [ssa-use] value | -| refinement.js:326:29:326:33 | [ssa-use] value | -| refinement.js:326:71:326:75 | [ssa-use] value | -| refinement.js:326:79:326:83 | [ssa-use] value | -| refinement.js:327:10:327:14 | [ssa-use] value | -| refinement.js:331:29:331:33 | [ssa-use] value | -| refinement.js:331:75:331:79 | [ssa-use] value | -| refinement.js:331:84:331:88 | [ssa-use] value | -| refinement.js:332:10:332:14 | [ssa-use] value | -| refinement.js:336:12:336:16 | [ssa-use] value | -| refinement.js:344:29:344:33 | [ssa-use] value | -| refinement.js:344:73:344:77 | [ssa-use] value | -| refinement.js:344:83:344:87 | [ssa-use] value | -| refinement.js:345:10:345:14 | [ssa-use] value | -| refinement.js:349:29:349:33 | [ssa-use] value | -| refinement.js:349:81:349:85 | [ssa-use] value | -| refinement.js:349:99:349:103 | [ssa-use] value | -| refinement.js:350:10:350:14 | [ssa-use] value | -| refinement.js:354:29:354:33 | [ssa-use] value | -| refinement.js:354:67:354:71 | [ssa-use] value | -| refinement.js:354:84:354:88 | [ssa-use] value | -| refinement.js:355:10:355:14 | [ssa-use] value | -| refinement.js:359:29:359:33 | [ssa-use] value | -| refinement.js:359:66:359:70 | [ssa-use] value | -| refinement.js:359:75:359:79 | [ssa-use] value | -| refinement.js:360:10:360:14 | [ssa-use] value | -| refinement.js:364:29:364:33 | [ssa-use] value | -| refinement.js:364:66:364:70 | [ssa-use] value | -| refinement.js:364:100:364:104 | [ssa-use] value | -| refinement.js:365:10:365:14 | [ssa-use] value | -| refinement.js:370:7:370:11 | [ssa-use] value | -| refinement.js:370:46:370:50 | [ssa-use] value | -| refinement.js:370:80:370:84 | [ssa-use] value | -| refinement.js:371:12:371:16 | [ssa-use] value | -| refinement.js:373:10:373:14 | [ssa-use] value | -| refinement.js:377:29:377:33 | [ssa-use] value | -| refinement.js:377:73:377:77 | [ssa-use] value | -| refinement.js:377:110:377:114 | [ssa-use] value | -| refinement.js:378:10:378:14 | [ssa-use] value | -| refinement.js:382:29:382:33 | [ssa-use] value | -| refinement.js:382:83:382:87 | [ssa-use] value | -| refinement.js:383:10:383:14 | [ssa-use] value | -| refinement.js:387:29:387:33 | [ssa-use] value | -| refinement.js:387:74:387:78 | [ssa-use] value | -| refinement.js:388:10:388:14 | [ssa-use] value | -| refinement.js:393:7:393:11 | [ssa-use] value | -| refinement.js:393:48:393:52 | [ssa-use] value | -| refinement.js:393:84:393:88 | [ssa-use] value | -| refinement.js:395:10:395:14 | [ssa-use] value | -| refinement.js:400:24:400:28 | [ssa-use] input | -| refinement.js:402:29:402:33 | [ssa-use] value | -| refinement.js:402:76:402:80 | [ssa-use] value | -| refinement.js:402:84:402:87 | [ssa-use] wrap | -| refinement.js:402:89:402:93 | [ssa-use] value | -| refinement.js:403:10:403:14 | [ssa-use] value | -| refinement.js:407:29:407:33 | [ssa-use] value | -| refinement.js:407:66:407:70 | [ssa-use] value | -| refinement.js:407:80:407:84 | [ssa-use] value | -| refinement.js:408:10:408:14 | [ssa-use] value | -| refinement.js:412:29:412:33 | [ssa-use] value | -| refinement.js:412:71:412:75 | [ssa-use] value | -| refinement.js:412:85:412:89 | [ssa-use] value | -| refinement.js:413:10:413:14 | [ssa-use] value | -| refinement.js:418:29:418:33 | [ssa-use] value | -| refinement.js:418:63:418:67 | [ssa-use] value | -| refinement.js:418:89:418:93 | [ssa-use] value | -| refinement.js:419:10:419:14 | [ssa-use] value | -| refinement.js:424:29:424:33 | [ssa-use] value | -| refinement.js:424:71:424:75 | [ssa-use] value | -| refinement.js:424:79:424:83 | [ssa-use] clone | -| refinement.js:424:85:424:89 | [ssa-use] value | -| refinement.js:425:10:425:14 | [ssa-use] value | -| refinement.js:430:7:430:11 | [ssa-use] value | -| refinement.js:431:7:431:11 | [ssa-use] value | -| refinement.js:431:15:431:23 | [ssa-use] condition | -| refinement.js:431:34:431:38 | [ssa-use] value | -| refinement.js:431:72:431:76 | [ssa-use] value | -| refinement.js:433:10:433:14 | [ssa-use] value | -| refinement.js:438:7:438:11 | [ssa-use] value | -| refinement.js:439:7:439:11 | [ssa-use] value | -| refinement.js:439:15:439:23 | [ssa-use] condition | -| refinement.js:439:34:439:38 | [ssa-use] value | -| refinement.js:439:72:439:76 | [ssa-use] value | -| refinement.js:441:10:441:14 | [ssa-use] value | -| refinement.js:445:29:445:33 | [ssa-use] value | -| refinement.js:445:72:445:76 | [ssa-use] value | -| refinement.js:445:94:445:98 | [ssa-use] value | -| refinement.js:446:10:446:14 | [ssa-use] value | -| refinement.js:450:29:450:33 | [ssa-use] value | -| refinement.js:450:78:450:82 | [ssa-use] value | -| refinement.js:450:98:450:102 | [ssa-use] value | -| refinement.js:451:10:451:14 | [ssa-use] value | -| refinement.js:455:29:455:33 | [ssa-use] value | -| refinement.js:455:65:455:69 | [ssa-use] value | -| refinement.js:455:82:455:86 | [ssa-use] value | -| refinement.js:456:10:456:14 | [ssa-use] value | -| refinement.js:460:29:460:33 | [ssa-use] value | -| refinement.js:460:65:460:69 | [ssa-use] value | -| refinement.js:461:10:461:14 | [ssa-use] value | -| refinement.js:465:5:465:9 | [ssa-use] value | -| refinement.js:465:23:465:27 | [ssa-use] value | -| refinement.js:466:10:466:14 | [ssa-use] value | -| refinement.js:470:17:470:21 | [ssa-use] value | -| refinement.js:471:5:471:9 | [ssa-use] alias | -| refinement.js:472:29:472:33 | [ssa-use] value | -| refinement.js:472:75:472:79 | [ssa-use] value | -| refinement.js:472:83:472:87 | [ssa-use] alias | -| refinement.js:473:10:473:14 | [ssa-use] value | -| refinement.js:478:11:478:19 | [ssa-use] condition | -| refinement.js:479:14:479:26 | [ssa-synth-read] this | -| refinement.js:479:22:479:25 | [ssa-use] this | -| refinement.js:481:14:481:26 | [ssa-synth-read] this | -| refinement.js:481:22:481:25 | [ssa-use] this | -| refinement.js:483:12:483:15 | [ssa-use] this | -| refinement.js:487:7:487:10 | [ssa-use] this | -| refinement.js:488:20:488:23 | [ssa-use] this | -| refinement.js:489:20:489:23 | [ssa-use] this | -| refinement.js:490:12:490:15 | [ssa-use] this | -| tst.js:4:5:4:26 | [ssa-use] compati ... iSource | -| tst.js:4:30:4:34 | [ssa-use] start | -| tst.js:5:5:5:26 | [ssa-use] compati ... iSource | -| tst.js:5:30:5:32 | [ssa-use] end | -| tst.js:6:5:6:26 | [ssa-use] compati ... iSource | -| tst.js:6:5:6:28 | [ssa-synth-read] end | -| tst.js:9:8:9:29 | [ssa-use] compati ... iSource | orphanSsaDefinitionNode ssaDefinitionHasAstNode unmappedWriteDefSourceNode nonUniqueSharedSsaNodeMapping -| local.js:186:7:186:11 | super [postupdate] | 2 | -| local.js:188:7:188:11 | super [postupdate] | 2 | sharedReadContainerMismatch postUpdateMustFlow localFlowIsLocal -| local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | local.js:182:3:182:33 | implicit 'this' | Local flow step does not preserve enclosing callable. | -| local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | local.js:190:9:190:12 | [ssa-use] this | Local flow step does not preserve enclosing callable. | -| local.js:182:11:182:14 | [post update] this | local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | Local flow step does not preserve enclosing callable. | -| local.js:182:11:182:14 | [ssa-use] this | local.js:182:3:182:33 | [ssa-use] field = ... 1 : 2; | Local flow step does not preserve enclosing callable. | -| local.js:190:9:190:12 | [ssa-use] this | local.js:190:9:190:12 | this | Local flow step does not preserve enclosing callable. | diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql index edf1b59d40cd..74077540309d 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/invariants.ql @@ -1,6 +1,5 @@ import javascript import semmle.javascript.dataflow.internal.DataFlowNode -import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate import semmle.javascript.dataflow.internal.DataFlowImplConsistency as DataFlowImplConsistency import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2 import Ssa2::Consistency @@ -20,13 +19,13 @@ query predicate nonUniqueSsaVariable(DataFlow::SsaDefinitionNode node, int varia query predicate missingSsaNodeMetadata(DataFlow::Node node) { ( - node instanceof TSsaDefNode or - node instanceof TSsaUseNode or + node instanceof TSharedSsaDefNode or + node instanceof TSharedSsaReadNode or node instanceof TSsaSynthReadNode ) and not ( exists(node.toString()) and - (exists(node.getBasicBlock()) or node instanceof TSsaUseNode) and + (exists(node.getBasicBlock()) or node instanceof TSharedSsaReadNode) and exists(node.getContainer()) and exists(node.getLocation()) and exists(node.getFile()) @@ -34,7 +33,7 @@ query predicate missingSsaNodeMetadata(DataFlow::Node node) { } query predicate orphanSsaDefinitionNode(DataFlow::Node node) { - node instanceof TSsaDefNode and + node instanceof TSharedSsaDefNode and not node instanceof DataFlow::SsaDefinitionNode } @@ -43,18 +42,18 @@ query predicate ssaDefinitionHasAstNode(DataFlow::SsaDefinitionNode node, AstNod } query predicate unmappedWriteDefSourceNode(Ssa2::WriteDefSourceNode node, int mapped) { - mapped = count(DataFlowPrivate::getNodeFromSsa2(node)) and + mapped = count(DataFlow::getNodeFromSharedSsa(node)) and mapped != 1 } query predicate nonUniqueSharedSsaNodeMapping(Ssa2::Node node, int mapped) { - mapped = count(DataFlowPrivate::getNodeFromSsa2(node)) and + mapped = count(DataFlow::getNodeFromSharedSsa(node)) and mapped > 1 } query predicate sharedReadContainerMismatch(Ssa2::ExprNode read) { - TSsaUseNode(read.getExpr()).(DataFlow::Node).getContainer() != - DataFlowPrivate::getNodeFromSsa2(read).(DataFlow::Node).getContainer() + TSharedSsaReadNode(read).(DataFlow::Node).getContainer() != + DataFlow::getNodeFromSharedSsa(read).(DataFlow::Node).getContainer() } query predicate postUpdateMustFlow(DataFlow::PostUpdateNode update, DataFlow::Node node) { diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/local.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.js index 5bc3a3ffa56e..1b75d67293a1 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/local.js +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.js @@ -15,21 +15,21 @@ function ordinaryPhiLocalFlow(condition, otherCondition) { function postUpdateOrdering(value) { SINK(value); // $ noPostUpdateFlow=post-update value.property = SOURCE("post-update"); - SINK(value); // $ SPURIOUS: noPostUpdateFlow=post-update MISSING: postUpdateFlow=post-update + SINK(value); // $ postUpdateFlow=post-update } function assignmentUpdateCompletion(value) { - value.property = SOURCE("store-completion", SINK(value)); // $ noPostUpdateFlow=store-completion SPURIOUS: globalPostUpdateFlow=store-completion MISSING: noGlobalPostUpdateFlow=store-completion - SINK(value); // $ globalPostUpdateFlow=store-completion SPURIOUS: noPostUpdateFlow=store-completion MISSING: postUpdateFlow=store-completion + value.property = SOURCE("store-completion", SINK(value)); // $ noPostUpdateFlow=store-completion noGlobalPostUpdateFlow=store-completion + SINK(value); // $ postUpdateFlow=store-completion globalPostUpdateFlow=store-completion } function callUpdateCompletion(value) { - UPDATE("call-completion", value, SINK(value)); // $ noPostUpdateFlow=call-completion SPURIOUS: globalPostUpdateFlow=call-completion MISSING: noGlobalPostUpdateFlow=call-completion - SINK(value); // $ globalPostUpdateFlow=call-completion SPURIOUS: noPostUpdateFlow=call-completion MISSING: postUpdateFlow=call-completion + UPDATE("call-completion", value, SINK(value)); // $ noPostUpdateFlow=call-completion noGlobalPostUpdateFlow=call-completion + SINK(value); // $ postUpdateFlow=call-completion globalPostUpdateFlow=call-completion } function nestedCallUpdateCompletion(value) { - use(UPDATE("nested-call-completion", value), SINK(value)); // $ globalPostUpdateFlow=nested-call-completion SPURIOUS: noPostUpdateFlow=nested-call-completion MISSING: postUpdateFlow=nested-call-completion + use(UPDATE("nested-call-completion", value), SINK(value)); // $ postUpdateFlow=nested-call-completion globalPostUpdateFlow=nested-call-completion } function overwrittenCallArgument(value) { @@ -39,17 +39,17 @@ function overwrittenCallArgument(value) { function selfAssignedCallUpdate(value) { UPDATE("self-assigned-call-update", value, value = value); - SINK(value); // $ globalPostUpdateFlow=self-assigned-call-update SPURIOUS: noPostUpdateFlow=self-assigned-call-update MISSING: postUpdateFlow=self-assigned-call-update + SINK(value); // $ postUpdateFlow=self-assigned-call-update globalPostUpdateFlow=self-assigned-call-update } function selfAssignedStoreUpdate(value) { value.property = (value = value, SOURCE("self-assigned-store-update")); - SINK(value); // $ globalPostUpdateFlow=self-assigned-store-update SPURIOUS: noPostUpdateFlow=self-assigned-store-update MISSING: postUpdateFlow=self-assigned-store-update + SINK(value); // $ postUpdateFlow=self-assigned-store-update globalPostUpdateFlow=self-assigned-store-update } function conditionalCallUpdate(value, condition) { UPDATE("conditional-call-update", value, value = condition ? value : {}); - SINK(value); // $ globalPostUpdateFlow=conditional-call-update SPURIOUS: noPostUpdateFlow=conditional-call-update MISSING: postUpdateFlow=conditional-call-update + SINK(value); // $ postUpdateFlow=conditional-call-update globalPostUpdateFlow=conditional-call-update } function unusedOverwrittenCallArgument(value) { @@ -58,38 +58,38 @@ function unusedOverwrittenCallArgument(value) { function refinedCallArgument(value) { UPDATE("refined-call-argument", value, typeof value === "object" ? 1 : 2); - SINK(value); // $ globalPostUpdateFlow=refined-call-argument SPURIOUS: noPostUpdateFlow=refined-call-argument MISSING: postUpdateFlow=refined-call-argument + SINK(value); // $ postUpdateFlow=refined-call-argument globalPostUpdateFlow=refined-call-argument } function computedStoreCompletion(value) { value[ - SINK(value) // $ noPostUpdateFlow=computed-store-completion SPURIOUS: globalPostUpdateFlow=computed-store-completion MISSING: noGlobalPostUpdateFlow=computed-store-completion + SINK(value) // $ noPostUpdateFlow=computed-store-completion noGlobalPostUpdateFlow=computed-store-completion ] = SOURCE( "computed-store-completion", - SINK(value) // $ noPostUpdateFlow=computed-store-completion SPURIOUS: globalPostUpdateFlow=computed-store-completion MISSING: noGlobalPostUpdateFlow=computed-store-completion + SINK(value) // $ noPostUpdateFlow=computed-store-completion noGlobalPostUpdateFlow=computed-store-completion ); - SINK(value); // $ globalPostUpdateFlow=computed-store-completion SPURIOUS: noPostUpdateFlow=computed-store-completion MISSING: postUpdateFlow=computed-store-completion + SINK(value); // $ postUpdateFlow=computed-store-completion globalPostUpdateFlow=computed-store-completion } function destructuringStoreCompletion(value) { - [value.first, value[SINK(value)]] = SOURCE("destructuring-store-completion"); // $ globalPostUpdateFlow=destructuring-store-completion SPURIOUS: noPostUpdateFlow=destructuring-store-completion MISSING: postUpdateFlow=destructuring-store-completion - SINK(value); // $ globalPostUpdateFlow=destructuring-store-completion SPURIOUS: noPostUpdateFlow=destructuring-store-completion MISSING: postUpdateFlow=destructuring-store-completion + [value.first, value[SINK(value)]] = SOURCE("destructuring-store-completion"); // $ postUpdateFlow=destructuring-store-completion globalPostUpdateFlow=destructuring-store-completion + SINK(value); // $ postUpdateFlow=destructuring-store-completion globalPostUpdateFlow=destructuring-store-completion } function exceptionalCallUpdate(value) { try { UPDATE("exceptional-call-completion", value); } catch (error) { - SINK(value); // $ globalPostUpdateFlow=exceptional-call-completion SPURIOUS: noPostUpdateFlow=exceptional-call-completion MISSING: postUpdateFlow=exceptional-call-completion + SINK(value); // $ postUpdateFlow=exceptional-call-completion globalPostUpdateFlow=exceptional-call-completion } - SINK(value); // $ globalPostUpdateFlow=exceptional-call-completion SPURIOUS: noPostUpdateFlow=exceptional-call-completion MISSING: postUpdateFlow=exceptional-call-completion + SINK(value); // $ postUpdateFlow=exceptional-call-completion globalPostUpdateFlow=exceptional-call-completion } function loopUpdateCompletion(value) { while (condition()) { - SINK(value); // $ globalPostUpdateFlow=loop-completion SPURIOUS: noPostUpdateFlow=loop-completion MISSING: postUpdateFlow=loop-completion + SINK(value); // $ postUpdateFlow=loop-completion globalPostUpdateFlow=loop-completion UPDATE("loop-completion", value); - SINK(value); // $ globalPostUpdateFlow=loop-completion SPURIOUS: noPostUpdateFlow=loop-completion MISSING: postUpdateFlow=loop-completion + SINK(value); // $ postUpdateFlow=loop-completion globalPostUpdateFlow=loop-completion } } @@ -106,7 +106,7 @@ function nestedRefinementPostUpdate(value) { if (value) { if (typeof value === "object") { value.property = SOURCE("nested-post-update"); - SINK(value); // $ SPURIOUS: noPostUpdateFlow=nested-post-update MISSING: postUpdateFlow=nested-post-update + SINK(value); // $ postUpdateFlow=nested-post-update } } } @@ -116,7 +116,7 @@ function refinedPostUpdateReads(value) { SINK(value); // $ noPostUpdateFlow=refined-post-update value.property = SOURCE("refined-post-update"); use(value); - SINK(value); // $ SPURIOUS: noPostUpdateFlow=refined-post-update MISSING: postUpdateFlow=refined-post-update + SINK(value); // $ postUpdateFlow=refined-post-update } } @@ -125,7 +125,7 @@ function compatibilityPhiPostUpdateReads(value) { SINK(value); // $ noPostUpdateFlow=compatibility-phi-post-update value.property = SOURCE("compatibility-phi-post-update"); use(value); - SINK(value); // $ SPURIOUS: noPostUpdateFlow=compatibility-phi-post-update MISSING: postUpdateFlow=compatibility-phi-post-update + SINK(value); // $ postUpdateFlow=compatibility-phi-post-update } } @@ -133,7 +133,7 @@ function postUpdateBeforeNestedRefinement(value) { if (value) { value.property = SOURCE("update-before-refinement"); if (typeof value === "object") { - SINK(value); // $ SPURIOUS: noPostUpdateFlow=update-before-refinement MISSING: postUpdateFlow=update-before-refinement + SINK(value); // $ postUpdateFlow=update-before-refinement } } } @@ -143,12 +143,12 @@ function postUpdateBeforeCompatibilityPhi(value) { value.property = SOURCE("update-before-phi"); use(value); } - SINK(value); // $ SPURIOUS: noPostUpdateFlow=update-before-phi MISSING: postUpdateFlow=update-before-phi + SINK(value); // $ postUpdateFlow=update-before-phi } function postUpdateImmediatePredecessor(value) { value.property = SOURCE("update-immediate-predecessor"); - SINK(value); // $ noImmediatePostUpdate=update-immediate-predecessor SPURIOUS: noPostUpdateFlow=update-immediate-predecessor MISSING: postUpdateFlow=update-immediate-predecessor + SINK(value); // $ postUpdateFlow=update-immediate-predecessor noImmediatePostUpdate=update-immediate-predecessor } function capturedRefinementLocalFlow() { @@ -179,7 +179,7 @@ function unreachableLocalSsaCode() { class SharedSsaBase {} class SharedSsaDerived extends SharedSsaBase { - field = this.condition ? 1 : 2; // $ SPURIOUS: fieldReadContainerMismatch + field = this.condition ? 1 : 2; constructor(condition) { if (condition) { diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql index fda73fc7f6fb..9e8da0b33f03 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/local.ql @@ -149,7 +149,7 @@ module InlineTest implements TestSig { value = "" and exists(FieldDefinition field, Ssa2::ExprNode read, DataFlow::Node node | read.getExpr() = field and - node = TSsaUseNode(read.getExpr()) and + node = TSharedSsaReadNode(read) and node.getContainer() != field.getDeclaringClass().getConstructor().getBody() and location = field.getLocation() ) diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js index 0b57e9e2743d..ce456e295c4a 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.js @@ -67,7 +67,7 @@ function sharedDefinitionApi(parameter) { const { value } = { value: parameter }; CHECK_NATIVE(value); // $ sharedDefinition if (typeof value === "object") { - CHECK_NATIVE(value); // $ MISSING: sharedDefinition + CHECK_NATIVE(value); // $ sharedDefinition } } @@ -78,11 +78,11 @@ function capturedDefinitionApi() { value = 2; } function* read() { - CHECK_NATIVE(value); // $ MISSING: sharedDefinition + CHECK_NATIVE(value); // $ sharedDefinition yield; - CHECK_NATIVE(value); // $ MISSING: sharedDefinition + CHECK_NATIVE(value); // $ sharedDefinition } write(); - CHECK_NATIVE(value); // $ MISSING: sharedDefinition + CHECK_NATIVE(value); // $ sharedDefinition return read; } diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql index dfc888041705..f936e7f0209b 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/nodes.ql @@ -31,21 +31,14 @@ module InlineTest implements TestSig { tag = "sharedDefinition" and exists( DataFlow::InvokeNode check, VarUse read, Ssa2::Definition definition, - Ssa2::SsaConfig::SourceVariable variable, BasicBlock bb, int index, BasicBlock defBlock, - int publicIndex, int nativeIndex + Ssa2::SsaConfig::SourceVariable variable, BasicBlock bb, int index | check.getCalleeName() = "CHECK_NATIVE" and read = check.getArgument(0).asExpr() and read = bb.getNode(index) and variable.asLocalVariable() = read.getVariable() and Ssa2::ssaDefReachesRead(variable, definition, bb, index) and - definition.definesAt(variable, defBlock, nativeIndex) and - read.getSsaVariable().getDefinition().definesAt(defBlock, publicIndex, read.getVariable()) and - ( - publicIndex = nativeIndex and nativeIndex >= 0 - or - publicIndex = 0 and nativeIndex = -1 - ) and + read.getSsaVariable().getDefinition() = definition and location = check.getLocation() ) or diff --git a/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js b/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js index 97b733082133..6ebc757ea2d4 100644 --- a/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js +++ b/javascript/ql/test/library-tests/SharedSsaCompatibility/refinement.js @@ -22,7 +22,7 @@ function phiReadInsideRefinement(condition) { } else { if (!BARRIER(phiReadSource)) return; } - SINK(phiReadSource); // $ localRefinementFlow=refined-phi-read noRefinementBypass=refined-phi-read SPURIOUS: refinementFlow=refined-phi-read refinementTaint=refined-phi-read MISSING: noRefinementFlow=refined-phi-read noRefinementTaint=refined-phi-read + SINK(phiReadSource); // $ noRefinementFlow=refined-phi-read noRefinementTaint=refined-phi-read localRefinementFlow=refined-phi-read noRefinementBypass=refined-phi-read } } @@ -155,7 +155,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { if (!BARRIER(value)) return; } if (typeof value === "object") { - SINK(value); // $ localRefinementFlow=refinement-after-guarded-join noRefinementBypass=refinement-after-guarded-join SPURIOUS: refinementFlow=refinement-after-guarded-join refinementTaint=refinement-after-guarded-join MISSING: noRefinementFlow=refinement-after-guarded-join noRefinementTaint=refinement-after-guarded-join + SINK(value); // $ localRefinementFlow=refinement-after-guarded-join noRefinementBypass=refinement-after-guarded-join noRefinementFlow=refinement-after-guarded-join noRefinementTaint=refinement-after-guarded-join } } } @@ -219,7 +219,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { } else { value = "safe"; } - SINK(value); // $ localRefinementFlow=indirect-barrier-read-join SPURIOUS: refinementFlow=indirect-barrier-read-join refinementTaint=indirect-barrier-read-join MISSING: noRefinementFlow=indirect-barrier-read-join noRefinementTaint=indirect-barrier-read-join + SINK(value); // $ localRefinementFlow=indirect-barrier-read-join noRefinementFlow=indirect-barrier-read-join noRefinementTaint=indirect-barrier-read-join } function indirectBarrierGuardEmptyBranchBeforeJoin() { @@ -229,7 +229,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { } else { value = "safe"; } - SINK(value); // $ localRefinementFlow=indirect-barrier-empty-join SPURIOUS: refinementFlow=indirect-barrier-empty-join refinementTaint=indirect-barrier-empty-join MISSING: noRefinementFlow=indirect-barrier-empty-join noRefinementTaint=indirect-barrier-empty-join + SINK(value); // $ localRefinementFlow=indirect-barrier-empty-join noRefinementFlow=indirect-barrier-empty-join noRefinementTaint=indirect-barrier-empty-join } function indirectBarrierGuardAfterRefinementBeforeJoin() { @@ -240,7 +240,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { } else { value = "safe"; } - SINK(value); // $ localRefinementFlow=indirect-barrier-after-refinement-join noRefinementBypass=indirect-barrier-after-refinement-join SPURIOUS: refinementFlow=indirect-barrier-after-refinement-join refinementTaint=indirect-barrier-after-refinement-join MISSING: noRefinementFlow=indirect-barrier-after-refinement-join noRefinementTaint=indirect-barrier-after-refinement-join + SINK(value); // $ localRefinementFlow=indirect-barrier-after-refinement-join noRefinementBypass=indirect-barrier-after-refinement-join noRefinementFlow=indirect-barrier-after-refinement-join noRefinementTaint=indirect-barrier-after-refinement-join } } @@ -253,7 +253,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { value = "safe"; } } - SINK(value); // $ localRefinementFlow=barrier-in-with SPURIOUS: refinementFlow=barrier-in-with refinementTaint=barrier-in-with MISSING: noRefinementFlow=barrier-in-with noRefinementTaint=barrier-in-with + SINK(value); // $ localRefinementFlow=barrier-in-with noRefinementFlow=barrier-in-with noRefinementTaint=barrier-in-with } function mutatePreservedArgument(target, payload) { @@ -278,7 +278,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { function copiedArgument(value) { const alias = value; mutatePreservedArgument(value, SOURCE("copied-argument"), value = alias); - SINK(value.property); // $ SPURIOUS: noRefinementFlow=copied-argument noRefinementTaint=copied-argument MISSING: refinementFlow=copied-argument refinementTaint=copied-argument + SINK(value.property); // $ refinementFlow=copied-argument refinementTaint=copied-argument } function conditionalArgumentCopy(value, condition) { @@ -314,7 +314,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { function conditionalAliasArgument(value, condition) { const alias = condition ? value : {}; mutatePreservedArgument(value, SOURCE("conditional-alias-argument"), value = alias); - SINK(value.property); // $ SPURIOUS: noRefinementFlow=conditional-alias-argument noRefinementTaint=conditional-alias-argument MISSING: refinementFlow=conditional-alias-argument refinementTaint=conditional-alias-argument + SINK(value.property); // $ refinementFlow=conditional-alias-argument refinementTaint=conditional-alias-argument } function conditionalStoreCopy(value, condition) { @@ -368,7 +368,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { function identityCopyUpdateTiming(value) { mutatePreservedArgument( value, SOURCE("identity-copy-timing"), value = identityPreservedArgument(value), - SINK(value.property) // $ SPURIOUS: refinementFlow=identity-copy-timing refinementTaint=identity-copy-timing MISSING: noRefinementFlow=identity-copy-timing noRefinementTaint=identity-copy-timing + SINK(value.property) // $ noRefinementFlow=identity-copy-timing noRefinementTaint=identity-copy-timing ); SINK(value.property); // $ refinementFlow=identity-copy-timing refinementTaint=identity-copy-timing } @@ -480,7 +480,7 @@ function filteredPhiInputWithReplacement(condition, otherCondition) { } else { if (!BARRIER(this)) return; } - SINK(this); // $ localRefinementFlow=this-guard SPURIOUS: refinementFlow=this-guard refinementTaint=this-guard MISSING: noRefinementFlow=this-guard noRefinementTaint=this-guard + SINK(this); // $ localRefinementFlow=this-guard noRefinementFlow=this-guard noRefinementTaint=this-guard } occurrenceBarrierThisMethod() { diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 0083e55e642e..5109c89f9847 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -4,6 +4,7 @@ legacyDataFlowDifference | arrays-init.js:2:16:2:23 | source() | arrays-init.js:35:8:35:13 | arr[2] | only flow with OLD data flow library | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:36:8:36:13 | arr[3] | only flow with OLD data flow library | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:37:8:37:13 | arr[4] | only flow with OLD data flow library | +| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x | only flow with OLD data flow library | | bound-function.js:27:8:27:15 | source() | bound-function.js:30:10:30:10 | y | only flow with OLD data flow library | | call-apply.js:27:14:27:21 | source() | call-apply.js:24:8:24:11 | arg1 | only flow with NEW data flow library | | call-apply.js:27:14:27:21 | source() | call-apply.js:32:6:32:35 | foo1.ap ... e, ""]) | only flow with NEW data flow library | @@ -31,7 +32,6 @@ legacyDataFlowDifference | object-bypass-sanitizer.js:35:29:35:36 | source() | object-bypass-sanitizer.js:23:14:23:20 | obj.foo | only flow with OLD data flow library | | object-bypass-sanitizer.js:35:29:35:36 | source() | object-bypass-sanitizer.js:28:10:28:30 | sanitiz ... bj).foo | only flow with OLD data flow library | | promise.js:12:20:12:27 | source() | promise.js:13:8:13:23 | resolver.promise | only flow with OLD data flow library | -| sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library | | spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | only flow with NEW data flow library | | spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | only flow with NEW data flow library | | tst.js:2:13:2:20 | source() | tst.js:17:10:17:10 | a | only flow with OLD data flow library | @@ -85,7 +85,6 @@ flow | arrays.js:2:15:2:22 | source() | arrays.js:21:10:21:19 | foo.at(-1) | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:4:8:4:8 | x | | 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:17:21:17:28 | source() | bound-function.js:5:10:5:16 | y.test2 | | bound-function.js:19:15:19:22 | source() | bound-function.js:6:10:6:16 | y.test3 | @@ -265,7 +264,6 @@ flow | sanitizer-guards.js:13:14:13:21 | source() | sanitizer-guards.js:26:9:26:14 | this.x | | 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:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | 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 | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 6335d6dbd49a..4f3002a8aa31 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -1,5 +1,6 @@ legacyDataFlowDifference | arrays-init.js:2:16:2:23 | source() | arrays-init.js:38:8:38:13 | arr[5] | only flow with NEW data flow library | +| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x | only flow with OLD data flow library | | bound-function.js:27:8:27:15 | source() | bound-function.js:30:10:30:10 | y | only flow with OLD data flow library | | call-apply.js:27:14:27:21 | source() | call-apply.js:24:8:24:11 | arg1 | only flow with NEW data flow library | | call-apply.js:27:14:27:21 | source() | call-apply.js:32:6:32:35 | foo1.ap ... e, ""]) | only flow with NEW data flow library | @@ -22,7 +23,6 @@ legacyDataFlowDifference | nested-props.js:14:15:14:22 | source() | nested-props.js:15:10:15:16 | obj.x.y | only flow with NEW data flow library | | nested-props.js:27:18:27:25 | source() | nested-props.js:28:10:28:14 | obj.x | only flow with NEW data flow library | | nested-props.js:51:22:51:29 | source() | nested-props.js:52:10:52:16 | obj.x.y | only flow with NEW data flow library | -| sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library | | spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | only flow with NEW data flow library | | spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | only flow with NEW data flow library | | tst.js:2:13:2:20 | source() | tst.js:35:14:35:16 | ary | only flow with NEW data flow library | @@ -44,7 +44,6 @@ flow | booleanOps.js:2:11:2:18 | source() | booleanOps.js:7:10:7:10 | x | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:10:10:10:10 | x | | 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:17:21:17:28 | source() | bound-function.js:5:10:5:16 | y.test2 | | bound-function.js:19:15:19:22 | source() | bound-function.js:6:10:6:16 | y.test3 | @@ -174,7 +173,6 @@ flow | 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:43:11:43:18 | source() | sanitizer-guards.js:52:10:52:10 | x | -| sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | 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 | diff --git a/javascript/ql/test/library-tests/TaintTracking/booleanOps.js b/javascript/ql/test/library-tests/TaintTracking/booleanOps.js index 6cb0d6cea338..55bec4306aec 100644 --- a/javascript/ql/test/library-tests/TaintTracking/booleanOps.js +++ b/javascript/ql/test/library-tests/TaintTracking/booleanOps.js @@ -16,7 +16,7 @@ function test() { sink(x); // OK if (isSafe(x, y) || isSafe(x, z)) - sink(x); // OK [INCONSISTENCY] + sink(x); // OK if (isSafe(x) || 1 === 1) sink(x); // NOT OK diff --git a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js index 14f4139ca083..bccd4f1f0f17 100644 --- a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js +++ b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js @@ -61,7 +61,7 @@ function phi() { } else { x = null; } - sink(x); // OK [INCONSISTENCY] - dataflow2 cannot block the phi edge + sink(x); // OK } function phi2() { diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected b/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected index 1560c2076bc1..8a10bcd8841a 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected @@ -59,6 +59,8 @@ | scope for
... | dev-guide-5.js:4:47:4:52 | $scope | | scope for
... | dev-guide-5.js:5:3:5:8 | $scope | | scope for
... | dev-guide-5.js:5:3:5:8 | $scope | +| scope for
... | dev-guide-5.js:5:3:5:64 | [ssa-synth-read] $scope | +| scope for
... | dev-guide-5.js:5:3:5:64 | [ssa-synth-read] $scope | | scope for
... | dev-guide-5.js:6:3:6:8 | $scope | | scope for
... | dev-guide-5.js:6:3:6:8 | $scope | | scope for
... | dev-guide-6.js:4:47:4:52 | $scope | @@ -67,6 +69,8 @@ | scope for
... | dev-guide-6.js:4:47:4:52 | $scope | | scope for
... | dev-guide-6.js:5:3:5:8 | $scope | | scope for
... | dev-guide-6.js:5:3:5:8 | $scope | +| scope for
... | dev-guide-6.js:5:3:5:64 | [ssa-synth-read] $scope | +| scope for
... | dev-guide-6.js:5:3:5:64 | [ssa-synth-read] $scope | | scope for
... | dev-guide-6.js:6:3:6:8 | $scope | | scope for
... | dev-guide-6.js:6:3:6:8 | $scope | | scope for ... | scope-access.js:59:52:59:57 | $scope | @@ -116,18 +120,22 @@ | scope in dev-guide-5.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-5.js:5:3:5:8 | $scope | +| scope in dev-guide-5.html | dev-guide-5.js:5:3:5:64 | [ssa-synth-read] $scope | | scope in dev-guide-5.html | dev-guide-5.js:6:3:6:8 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:5:3:5:8 | $scope | +| scope in dev-guide-5.html | dev-guide-6.js:5:3:5:64 | [ssa-synth-read] $scope | | scope in dev-guide-5.html | dev-guide-6.js:6:3:6:8 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:5:3:5:8 | $scope | +| scope in dev-guide-6.html | dev-guide-5.js:5:3:5:64 | [ssa-synth-read] $scope | | scope in dev-guide-6.html | dev-guide-5.js:6:3:6:8 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:5:3:5:8 | $scope | +| scope in dev-guide-6.html | dev-guide-6.js:5:3:5:64 | [ssa-synth-read] $scope | | scope in dev-guide-6.html | dev-guide-6.js:6:3:6:8 | $scope | | scope in scope-access.html | scope-access.js:54:34:54:39 | $scope | | scope in scope-access.html | scope-access.js:54:34:54:39 | $scope | diff --git a/javascript/ql/test/library-tests/frameworks/Electron/tests.expected b/javascript/ql/test/library-tests/frameworks/Electron/tests.expected index a51c8e632b18..52f9836fae72 100644 --- a/javascript/ql/test/library-tests/frameworks/Electron/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Electron/tests.expected @@ -14,6 +14,8 @@ browserObject | electron.js:62:7:62:9 | win | | electron.js:62:13:62:59 | new Bro ... 1500 }) | | electron.js:63:3:63:5 | win | +| electron.js:63:3:63:13 | [ssa-synth-read] win | +| electron.js:63:3:63:34 | [ssa-synth-read] win | | electron.js:65:18:65:20 | win | | electronTs.ts:3:12:3:13 | bw | | electronTs.ts:3:12:3:13 | bw | diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 9007a1ed984e..2eaa18989a19 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -84,6 +84,8 @@ test_isRequest | src/express3.js:4:32:4:34 | req | | src/express3.js:4:32:4:34 | req | | src/express3.js:5:14:5:16 | req | +| src/express3.js:5:14:5:22 | [ssa-synth-read] req | +| src/express3.js:5:14:5:32 | [ssa-synth-read] req | | src/express3.js:5:35:5:37 | req | | src/express3.js:10:22:10:24 | req | | src/express3.js:15:20:15:22 | req | @@ -91,30 +93,46 @@ test_isRequest | src/express4.js:4:32:4:34 | req | | src/express4.js:4:32:4:34 | req | | src/express4.js:5:27:5:29 | req | +| src/express4.js:5:27:5:35 | [ssa-synth-read] req | | src/express4.js:6:18:6:20 | req | +| src/express4.js:6:18:6:26 | [ssa-synth-read] req | | src/express4.js:7:18:7:20 | req | | src/express.js:4:32:4:34 | req | | src/express.js:4:32:4:34 | req | | src/express.js:5:16:5:18 | req | +| src/express.js:5:16:5:24 | [ssa-synth-read] req | +| src/express.js:5:16:5:34 | [ssa-synth-read] req | | src/express.js:6:26:6:28 | req | | src/express.js:16:28:16:30 | req | | src/express.js:22:39:22:41 | req | | src/express.js:22:39:22:41 | req | | src/express.js:23:3:23:5 | req | +| src/express.js:23:3:23:10 | [ssa-synth-read] req | | src/express.js:24:3:24:5 | req | +| src/express.js:24:3:24:12 | [ssa-synth-read] req | | src/express.js:25:3:25:5 | req | +| src/express.js:25:3:25:11 | [ssa-synth-read] req | | src/express.js:26:3:26:5 | req | +| src/express.js:26:3:26:9 | [ssa-synth-read] req | | src/express.js:27:3:27:5 | req | +| src/express.js:27:3:27:17 | [ssa-synth-read] req | | src/express.js:28:3:28:5 | req | +| src/express.js:28:3:28:9 | [ssa-synth-read] req | +| src/express.js:28:3:28:16 | [ssa-synth-read] req | | src/express.js:29:3:29:5 | req | +| src/express.js:29:3:29:12 | [ssa-synth-read] req | +| src/express.js:29:3:29:19 | [ssa-synth-read] req | | src/express.js:30:3:30:5 | req | | src/express.js:37:19:37:21 | req | | src/express.js:42:11:42:13 | req | | src/express.js:46:31:46:33 | req | | src/express.js:46:31:46:33 | req | | src/express.js:47:3:47:5 | req | +| src/express.js:47:3:47:13 | [ssa-synth-read] req | | src/express.js:48:3:48:5 | req | +| src/express.js:48:3:48:10 | [ssa-synth-read] req | | src/express.js:49:3:49:5 | req | +| src/express.js:49:3:49:14 | [ssa-synth-read] req | | src/express.js:50:3:50:5 | req | | src/express.js:53:32:53:34 | req | | src/express.js:53:32:53:34 | req | @@ -140,12 +158,16 @@ test_isRequest | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:6:5:6:7 | req | +| src/middleware-flow.js:6:5:6:21 | [ssa-synth-read] req | | src/middleware-flow.js:7:5:7:7 | req | +| src/middleware-flow.js:7:5:7:12 | [ssa-synth-read] req | | src/middleware-flow.js:8:5:8:7 | req | | src/middleware-flow.js:17:25:17:27 | req | | src/middleware-flow.js:17:25:17:27 | req | | src/middleware-flow.js:18:9:18:11 | req | +| src/middleware-flow.js:18:9:18:14 | [ssa-synth-read] req | | src/middleware-flow.js:19:9:19:11 | req | +| src/middleware-flow.js:19:9:19:16 | [ssa-synth-read] req | | src/middleware-flow.js:20:9:20:11 | req | | src/middleware-flow.js:23:18:23:20 | req | | src/middleware-flow.js:23:18:23:20 | req | @@ -156,11 +178,14 @@ test_isRequest | src/middleware-flow.js:39:24:39:26 | req | | src/middleware-flow.js:39:24:39:26 | req | | src/middleware-flow.js:40:5:40:7 | req | +| src/middleware-flow.js:40:5:40:10 | [ssa-synth-read] req | | src/middleware-flow.js:41:5:41:7 | req | +| src/middleware-flow.js:41:5:41:12 | [ssa-synth-read] req | | src/middleware-flow.js:42:5:42:7 | req | | src/params.js:4:19:4:21 | req | | src/params.js:4:19:4:21 | req | | src/params.js:5:17:5:19 | req | +| src/params.js:5:17:5:25 | [ssa-synth-read] req | | src/params.js:6:17:6:19 | req | | src/params.js:14:33:14:35 | req | | src/passport.js:27:13:27:15 | req | @@ -288,6 +313,8 @@ test_isResponse | src/express3.js:4:37:4:39 | res | | src/express3.js:4:37:4:39 | res | | src/express3.js:5:3:5:5 | res | +| src/express3.js:5:3:5:12 | [ssa-synth-read] res | +| src/express3.js:5:3:5:51 | [ssa-synth-read] res | | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:6:3:6:5 | res | | src/express3.js:6:3:6:17 | res.send("val") | @@ -301,9 +328,15 @@ test_isResponse | src/express.js:4:37:4:39 | res | | src/express.js:4:37:4:39 | res | | src/express.js:5:3:5:5 | res | +| src/express.js:5:3:5:14 | [ssa-synth-read] res | +| src/express.js:5:3:5:35 | [ssa-synth-read] res | | src/express.js:6:3:6:5 | res | +| src/express.js:6:3:6:12 | [ssa-synth-read] res | +| src/express.js:6:3:6:45 | [ssa-synth-read] res | | src/express.js:6:3:6:45 | res.hea ... rget")) | | src/express.js:7:3:7:5 | res | +| src/express.js:7:3:7:12 | [ssa-synth-read] res | +| src/express.js:7:3:7:42 | [ssa-synth-read] res | | src/express.js:7:3:7:42 | res.hea ... plain") | | src/express.js:8:7:8:9 | res | | src/express.js:11:14:11:16 | arg | @@ -324,34 +357,52 @@ test_isResponse | src/express.js:53:37:53:39 | res | | src/express.js:53:37:53:39 | res | | src/express.js:54:3:54:5 | res | +| src/express.js:54:3:54:12 | [ssa-synth-read] res | +| src/express.js:54:3:54:41 | [ssa-synth-read] res | | src/express.js:54:3:54:41 | res.hea ... /html") | | src/express.js:55:3:55:5 | res | +| src/express.js:55:3:55:10 | [ssa-synth-read] res | +| src/express.js:55:3:55:26 | [ssa-synth-read] res | | src/express.js:55:3:55:26 | res.sen ... ms.foo) | | src/express.js:56:7:56:9 | res | | src/express.js:59:37:59:39 | res | | src/express.js:59:37:59:39 | res | | src/express.js:60:3:60:5 | res | +| src/express.js:60:3:60:12 | [ssa-synth-read] res | +| src/express.js:60:3:60:47 | [ssa-synth-read] res | | src/express.js:60:3:60:47 | res.hea ... n/xml") | | src/express.js:61:3:61:5 | res | +| src/express.js:61:3:61:10 | [ssa-synth-read] res | +| src/express.js:61:3:61:26 | [ssa-synth-read] res | | src/express.js:61:3:61:26 | res.sen ... ms.foo) | | src/express.js:62:7:62:9 | res | | src/express.js:65:41:65:43 | res | | src/express.js:65:41:65:43 | res | | src/express.js:66:3:66:5 | res | +| src/express.js:66:3:66:12 | [ssa-synth-read] res | +| src/express.js:66:3:66:42 | [ssa-synth-read] res | | src/express.js:66:3:66:42 | res.hea ... plain") | | src/express.js:67:3:67:5 | res | +| src/express.js:67:3:67:10 | [ssa-synth-read] res | +| src/express.js:67:3:67:26 | [ssa-synth-read] res | | src/express.js:67:3:67:26 | res.sen ... ms.foo) | | src/express.js:68:7:68:9 | res | | src/express.js:71:37:71:39 | res | | src/express.js:71:37:71:39 | res | | src/express.js:72:3:72:5 | res | +| src/express.js:72:3:72:12 | [ssa-synth-read] res | +| src/express.js:72:3:72:41 | [ssa-synth-read] res | | src/express.js:72:3:72:41 | res.hea ... /html") | | src/express.js:73:3:73:5 | res | +| src/express.js:73:3:73:10 | [ssa-synth-read] res | +| src/express.js:73:3:73:20 | [ssa-synth-read] res | | src/express.js:73:3:73:20 | res.send(req.path) | | src/express.js:74:7:74:9 | res | | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:5:2:5:4 | res | +| src/inheritedFromNode.js:5:2:5:8 | [ssa-synth-read] res | +| src/inheritedFromNode.js:5:2:5:10 | [ssa-synth-read] res | | src/inheritedFromNode.js:6:2:6:4 | res | | src/json.js:4:37:4:39 | res | | src/json.js:4:37:4:39 | res | @@ -389,36 +440,68 @@ test_isResponse | src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:19:5:19:7 | res | +| src/responseExprs.js:19:5:19:14 | [ssa-synth-read] res | +| src/responseExprs.js:19:5:19:16 | [ssa-synth-read] res | | src/responseExprs.js:19:5:19:16 | res.append() | | src/responseExprs.js:20:5:20:7 | res | +| src/responseExprs.js:20:5:20:18 | [ssa-synth-read] res | +| src/responseExprs.js:20:5:20:20 | [ssa-synth-read] res | | src/responseExprs.js:20:5:20:20 | res.attachment() | | src/responseExprs.js:21:5:21:7 | res | +| src/responseExprs.js:21:5:21:19 | [ssa-synth-read] res | +| src/responseExprs.js:21:5:21:21 | [ssa-synth-read] res | | src/responseExprs.js:21:5:21:21 | res.clearCookie() | | src/responseExprs.js:22:5:22:7 | res | +| src/responseExprs.js:22:5:22:19 | [ssa-synth-read] res | +| src/responseExprs.js:22:5:22:21 | [ssa-synth-read] res | | src/responseExprs.js:22:5:22:21 | res.contentType() | | src/responseExprs.js:23:5:23:7 | res | +| src/responseExprs.js:23:5:23:14 | [ssa-synth-read] res | +| src/responseExprs.js:23:5:23:16 | [ssa-synth-read] res | | src/responseExprs.js:23:5:23:16 | res.cookie() | | src/responseExprs.js:24:5:24:7 | res | +| src/responseExprs.js:24:5:24:14 | [ssa-synth-read] res | +| src/responseExprs.js:24:5:24:16 | [ssa-synth-read] res | | src/responseExprs.js:24:5:24:16 | res.format() | | src/responseExprs.js:25:5:25:7 | res | +| src/responseExprs.js:25:5:25:14 | [ssa-synth-read] res | +| src/responseExprs.js:25:5:25:16 | [ssa-synth-read] res | | src/responseExprs.js:25:5:25:16 | res.header() | | src/responseExprs.js:26:5:26:7 | res | +| src/responseExprs.js:26:5:26:13 | [ssa-synth-read] res | +| src/responseExprs.js:26:5:26:15 | [ssa-synth-read] res | | src/responseExprs.js:26:5:26:15 | res.links() | | src/responseExprs.js:27:5:27:7 | res | +| src/responseExprs.js:27:5:27:16 | [ssa-synth-read] res | +| src/responseExprs.js:27:5:27:18 | [ssa-synth-read] res | | src/responseExprs.js:27:5:27:18 | res.location() | | src/responseExprs.js:28:5:28:7 | res | +| src/responseExprs.js:28:5:28:12 | [ssa-synth-read] res | +| src/responseExprs.js:28:5:28:14 | [ssa-synth-read] res | | src/responseExprs.js:28:5:28:14 | res.send() | | src/responseExprs.js:29:5:29:7 | res | +| src/responseExprs.js:29:5:29:18 | [ssa-synth-read] res | +| src/responseExprs.js:29:5:29:20 | [ssa-synth-read] res | | src/responseExprs.js:29:5:29:20 | res.sendStatus() | | src/responseExprs.js:30:5:30:7 | res | +| src/responseExprs.js:30:5:30:11 | [ssa-synth-read] res | +| src/responseExprs.js:30:5:30:13 | [ssa-synth-read] res | | src/responseExprs.js:30:5:30:13 | res.set() | | src/responseExprs.js:31:5:31:7 | res | +| src/responseExprs.js:31:5:31:14 | [ssa-synth-read] res | +| src/responseExprs.js:31:5:31:16 | [ssa-synth-read] res | | src/responseExprs.js:31:5:31:16 | res.status() | | src/responseExprs.js:32:5:32:7 | res | +| src/responseExprs.js:32:5:32:12 | [ssa-synth-read] res | +| src/responseExprs.js:32:5:32:14 | [ssa-synth-read] res | | src/responseExprs.js:32:5:32:14 | res.type() | | src/responseExprs.js:33:5:33:7 | res | +| src/responseExprs.js:33:5:33:12 | [ssa-synth-read] res | +| src/responseExprs.js:33:5:33:14 | [ssa-synth-read] res | | src/responseExprs.js:33:5:33:14 | res.vary() | | src/responseExprs.js:35:5:35:7 | res | +| src/responseExprs.js:35:5:35:14 | [ssa-synth-read] res | +| src/responseExprs.js:35:5:35:16 | [ssa-synth-read] res | | src/responseExprs.js:35:5:35:16 | res.status() | | src/responseExprs.js:35:5:35:23 | res.status().send() | | src/responseExprs.js:37:5:37:19 | f(res.append()) | @@ -544,6 +627,8 @@ test_RequestExpr | src/express3.js:4:32:4:34 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:4:32:4:34 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:14:5:16 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:5:14:5:22 | [ssa-synth-read] req | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:5:14:5:32 | [ssa-synth-read] req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:35:5:37 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:10:22:10:24 | req | src/express3.js:10:12:10:32 | functio ... res){} | | src/express3.js:15:20:15:22 | req | src/express3.js:15:10:15:30 | functio ... res){} | @@ -551,30 +636,46 @@ test_RequestExpr | src/express4.js:4:32:4:34 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:4:32:4:34 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:5:27:5:29 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:5:27:5:35 | [ssa-synth-read] req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:6:18:6:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:6:18:6:26 | [ssa-synth-read] req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:7:18:7:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:32:4:34 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:4:32:4:34 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:5:16:5:18 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:5:16:5:24 | [ssa-synth-read] req | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:5:16:5:34 | [ssa-synth-read] req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:26:6:28 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:28:16:30 | req | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:39:22:41 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:22:39:22:41 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:23:3:23:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:23:3:23:10 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:24:3:24:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:24:3:24:12 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:25:3:25:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:25:3:25:11 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:26:3:26:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:26:3:26:9 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:27:3:27:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:27:3:27:17 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:28:3:28:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:28:3:28:9 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:28:3:28:16 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:29:3:29:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:29:3:29:12 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:29:3:29:19 | [ssa-synth-read] req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:30:3:30:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:37:19:37:21 | req | src/express.js:37:10:37:31 | functio ... es) { } | | src/express.js:42:11:42:13 | req | src/express.js:42:10:42:26 | (req, res) => f() | | src/express.js:46:31:46:33 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:46:31:46:33 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:47:3:47:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:47:3:47:13 | [ssa-synth-read] req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:48:3:48:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:48:3:48:10 | [ssa-synth-read] req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:49:3:49:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:49:3:49:14 | [ssa-synth-read] req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:50:3:50:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:53:32:53:34 | req | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:53:32:53:34 | req | src/express.js:53:23:57:1 | functio ... res);\\n} | @@ -600,12 +701,16 @@ test_RequestExpr | src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:6:5:6:7 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | +| src/middleware-flow.js:6:5:6:21 | [ssa-synth-read] req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:7:5:7:7 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | +| src/middleware-flow.js:7:5:7:12 | [ssa-synth-read] req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:8:5:8:7 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:17:25:17:27 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:17:25:17:27 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:18:9:18:11 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | +| src/middleware-flow.js:18:9:18:14 | [ssa-synth-read] req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:19:9:19:11 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | +| src/middleware-flow.js:19:9:19:16 | [ssa-synth-read] req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:20:9:20:11 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:23:18:23:20 | req | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | | src/middleware-flow.js:23:18:23:20 | req | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | @@ -616,11 +721,14 @@ test_RequestExpr | src/middleware-flow.js:39:24:39:26 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/middleware-flow.js:39:24:39:26 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/middleware-flow.js:40:5:40:7 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | +| src/middleware-flow.js:40:5:40:10 | [ssa-synth-read] req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/middleware-flow.js:41:5:41:7 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | +| src/middleware-flow.js:41:5:41:12 | [ssa-synth-read] req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/middleware-flow.js:42:5:42:7 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/params.js:4:19:4:21 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:4:19:4:21 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:5:17:5:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:5:17:5:25 | [ssa-synth-read] req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:6:17:6:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:14:33:14:35 | req | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/passport.js:27:13:27:15 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | @@ -764,6 +872,8 @@ test_ResponseExpr | src/express3.js:4:37:4:39 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:4:37:4:39 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:3:5:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:5:3:5:12 | [ssa-synth-read] res | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:5:3:5:51 | [ssa-synth-read] res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:3:5:51 | res.hea ... "val")) | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:17 | res.send("val") | src/express3.js:4:23:7:1 | functio ... al");\\n} | @@ -777,9 +887,15 @@ test_ResponseExpr | src/express.js:4:37:4:39 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:4:37:4:39 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:5:3:5:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:5:3:5:14 | [ssa-synth-read] res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:5:3:5:35 | [ssa-synth-read] res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:6:3:6:12 | [ssa-synth-read] res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:6:3:6:45 | [ssa-synth-read] res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:45 | res.hea ... rget")) | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:7:3:7:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:7:3:7:12 | [ssa-synth-read] res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:7:3:7:42 | [ssa-synth-read] res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:7:3:7:42 | res.hea ... plain") | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:8:7:8:9 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:11:14:11:16 | arg | src/express.js:4:23:9:1 | functio ... res);\\n} | @@ -816,34 +932,52 @@ test_ResponseExpr | src/express.js:53:37:53:39 | res | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:53:37:53:39 | res | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:54:3:54:5 | res | src/express.js:53:23:57:1 | functio ... res);\\n} | +| src/express.js:54:3:54:12 | [ssa-synth-read] res | src/express.js:53:23:57:1 | functio ... res);\\n} | +| src/express.js:54:3:54:41 | [ssa-synth-read] res | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:54:3:54:41 | res.hea ... /html") | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:55:3:55:5 | res | src/express.js:53:23:57:1 | functio ... res);\\n} | +| src/express.js:55:3:55:10 | [ssa-synth-read] res | src/express.js:53:23:57:1 | functio ... res);\\n} | +| src/express.js:55:3:55:26 | [ssa-synth-read] res | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:55:3:55:26 | res.sen ... ms.foo) | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:56:7:56:9 | res | src/express.js:53:23:57:1 | functio ... res);\\n} | | src/express.js:59:37:59:39 | res | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:59:37:59:39 | res | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:60:3:60:5 | res | src/express.js:59:23:63:1 | functio ... res);\\n} | +| src/express.js:60:3:60:12 | [ssa-synth-read] res | src/express.js:59:23:63:1 | functio ... res);\\n} | +| src/express.js:60:3:60:47 | [ssa-synth-read] res | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:60:3:60:47 | res.hea ... n/xml") | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:61:3:61:5 | res | src/express.js:59:23:63:1 | functio ... res);\\n} | +| src/express.js:61:3:61:10 | [ssa-synth-read] res | src/express.js:59:23:63:1 | functio ... res);\\n} | +| src/express.js:61:3:61:26 | [ssa-synth-read] res | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:61:3:61:26 | res.sen ... ms.foo) | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:62:7:62:9 | res | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:65:41:65:43 | res | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:65:41:65:43 | res | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:66:3:66:5 | res | src/express.js:65:27:69:1 | functio ... res);\\n} | +| src/express.js:66:3:66:12 | [ssa-synth-read] res | src/express.js:65:27:69:1 | functio ... res);\\n} | +| src/express.js:66:3:66:42 | [ssa-synth-read] res | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:66:3:66:42 | res.hea ... plain") | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:67:3:67:5 | res | src/express.js:65:27:69:1 | functio ... res);\\n} | +| src/express.js:67:3:67:10 | [ssa-synth-read] res | src/express.js:65:27:69:1 | functio ... res);\\n} | +| src/express.js:67:3:67:26 | [ssa-synth-read] res | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:67:3:67:26 | res.sen ... ms.foo) | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:68:7:68:9 | res | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:71:37:71:39 | res | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/express.js:71:37:71:39 | res | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/express.js:72:3:72:5 | res | src/express.js:71:23:75:1 | functio ... res);\\n} | +| src/express.js:72:3:72:12 | [ssa-synth-read] res | src/express.js:71:23:75:1 | functio ... res);\\n} | +| src/express.js:72:3:72:41 | [ssa-synth-read] res | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/express.js:72:3:72:41 | res.hea ... /html") | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/express.js:73:3:73:5 | res | src/express.js:71:23:75:1 | functio ... res);\\n} | +| src/express.js:73:3:73:10 | [ssa-synth-read] res | src/express.js:71:23:75:1 | functio ... res);\\n} | +| src/express.js:73:3:73:20 | [ssa-synth-read] res | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/express.js:73:3:73:20 | res.send(req.path) | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/express.js:74:7:74:9 | res | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:4:29:4:31 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:4:29:4:31 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:5:2:5:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/inheritedFromNode.js:5:2:5:8 | [ssa-synth-read] res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/inheritedFromNode.js:5:2:5:10 | [ssa-synth-read] res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:6:2:6:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/json.js:4:37:4:39 | res | src/json.js:4:23:6:1 | functio ... ata);\\n} | | src/json.js:4:37:4:39 | res | src/json.js:4:23:6:1 | functio ... ata);\\n} | @@ -881,36 +1015,68 @@ test_ResponseExpr | src/responseExprs.js:16:44:16:46 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:16:44:16:46 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:19:5:19:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:19:5:19:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:19:5:19:16 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:19:5:19:16 | res.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:20:5:20:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:20:5:20:18 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:20:5:20:20 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:20:5:20:20 | res.attachment() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:21:5:21:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:21:5:21:19 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:21:5:21:21 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:21:5:21:21 | res.clearCookie() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:22:5:22:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:22:5:22:19 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:22:5:22:21 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:22:5:22:21 | res.contentType() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:23:5:23:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:23:5:23:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:23:5:23:16 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:23:5:23:16 | res.cookie() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:24:5:24:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:24:5:24:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:24:5:24:16 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:24:5:24:16 | res.format() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:25:5:25:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:25:5:25:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:25:5:25:16 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:25:5:25:16 | res.header() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:26:5:26:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:26:5:26:13 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:26:5:26:15 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:26:5:26:15 | res.links() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:27:5:27:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:27:5:27:16 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:27:5:27:18 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:27:5:27:18 | res.location() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:28:5:28:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:28:5:28:12 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:28:5:28:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:28:5:28:14 | res.send() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:29:5:29:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:29:5:29:18 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:29:5:29:20 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:29:5:29:20 | res.sendStatus() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:30:5:30:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:30:5:30:11 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:30:5:30:13 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:30:5:30:13 | res.set() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:31:5:31:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:31:5:31:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:31:5:31:16 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:31:5:31:16 | res.status() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:32:5:32:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:32:5:32:12 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:32:5:32:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:32:5:32:14 | res.type() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:33:5:33:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:33:5:33:12 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:33:5:33:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:33:5:33:14 | res.vary() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:35:5:35:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:35:5:35:14 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:35:5:35:16 | [ssa-synth-read] res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:35:5:35:16 | res.status() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:35:5:35:23 | res.status().send() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:37:5:37:19 | f(res.append()) | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | @@ -1710,6 +1876,8 @@ test_RouteHandler_getARequestExpr | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:32:4:34 | req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:32:4:34 | req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:14:5:16 | req | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:14:5:22 | [ssa-synth-read] req | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:14:5:32 | [ssa-synth-read] req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:35:5:37 | req | | src/express3.js:10:12:10:32 | functio ... res){} | src/express3.js:10:22:10:24 | req | | src/express3.js:15:10:15:30 | functio ... res){} | src/express3.js:15:20:15:22 | req | @@ -1717,30 +1885,46 @@ test_RouteHandler_getARequestExpr | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:32:4:34 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:32:4:34 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:5:27:5:29 | req | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:5:27:5:35 | [ssa-synth-read] req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:6:18:6:20 | req | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:6:18:6:26 | [ssa-synth-read] req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:7:18:7:20 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:32:4:34 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:32:4:34 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:16:5:18 | req | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:16:5:24 | [ssa-synth-read] req | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:16:5:34 | [ssa-synth-read] req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:26:6:28 | req | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:28:16:30 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:5 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:10 | [ssa-synth-read] req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:24:3:24:5 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:24:3:24:12 | [ssa-synth-read] req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:25:3:25:5 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:25:3:25:11 | [ssa-synth-read] req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:26:3:26:5 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:26:3:26:9 | [ssa-synth-read] req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:27:3:27:5 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:27:3:27:17 | [ssa-synth-read] req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:28:3:28:5 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:28:3:28:9 | [ssa-synth-read] req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:28:3:28:16 | [ssa-synth-read] req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:29:3:29:5 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:29:3:29:12 | [ssa-synth-read] req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:29:3:29:19 | [ssa-synth-read] req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:30:3:30:5 | req | | src/express.js:37:10:37:31 | functio ... es) { } | src/express.js:37:19:37:21 | req | | src/express.js:42:10:42:26 | (req, res) => f() | src/express.js:42:11:42:13 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:47:3:47:5 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:47:3:47:13 | [ssa-synth-read] req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:48:3:48:5 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:48:3:48:10 | [ssa-synth-read] req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:5 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:14 | [ssa-synth-read] req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:50:3:50:5 | req | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:53:32:53:34 | req | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:53:32:53:34 | req | @@ -1766,12 +1950,16 @@ test_RouteHandler_getARequestExpr | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:6:5:6:7 | req | +| src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:6:5:6:21 | [ssa-synth-read] req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:7:5:7:7 | req | +| src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:7:5:7:12 | [ssa-synth-read] req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:8:5:8:7 | req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:25:17:27 | req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:25:17:27 | req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:18:9:18:11 | req | +| src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:18:9:18:14 | [ssa-synth-read] req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:19:9:19:11 | req | +| src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:19:9:19:16 | [ssa-synth-read] req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:20:9:20:11 | req | | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | src/middleware-flow.js:23:18:23:20 | req | | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | src/middleware-flow.js:23:18:23:20 | req | @@ -1782,11 +1970,14 @@ test_RouteHandler_getARequestExpr | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:39:24:39:26 | req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:39:24:39:26 | req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:40:5:40:7 | req | +| src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:40:5:40:10 | [ssa-synth-read] req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:41:5:41:7 | req | +| src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:41:5:41:12 | [ssa-synth-read] req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:42:5:42:7 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:19:4:21 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:19:4:21 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:5:17:5:19 | req | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:5:17:5:25 | [ssa-synth-read] req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:19 | req | | src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:33:14:35 | req | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:27:13:27:15 | req | @@ -1892,6 +2083,8 @@ test_RouteHandler_getAResponseExpr | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:37:4:39 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:37:4:39 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:5 | res | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:12 | [ssa-synth-read] res | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:51 | [ssa-synth-read] res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:5 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:17 | res.send("val") | @@ -1905,9 +2098,15 @@ test_RouteHandler_getAResponseExpr | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:37:4:39 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:37:4:39 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:3:5:5 | res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:3:5:14 | [ssa-synth-read] res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:3:5:35 | [ssa-synth-read] res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:5 | res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:12 | [ssa-synth-read] res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:45 | [ssa-synth-read] res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:45 | res.hea ... rget")) | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:7:3:7:5 | res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:7:3:7:12 | [ssa-synth-read] res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:7:3:7:42 | [ssa-synth-read] res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:7:3:7:42 | res.hea ... plain") | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:8:7:8:9 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:11:14:11:16 | arg | @@ -1932,8 +2131,12 @@ test_RouteHandler_getAResponseExpr | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:53:37:53:39 | res | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:53:37:53:39 | res | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:54:3:54:5 | res | +| src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:54:3:54:12 | [ssa-synth-read] res | +| src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:54:3:54:41 | [ssa-synth-read] res | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:54:3:54:41 | res.hea ... /html") | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:55:3:55:5 | res | +| src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:55:3:55:10 | [ssa-synth-read] res | +| src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:55:3:55:26 | [ssa-synth-read] res | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:55:3:55:26 | res.sen ... ms.foo) | | src/express.js:53:23:57:1 | functio ... res);\\n} | src/express.js:56:7:56:9 | res | | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:11:14:11:16 | arg | @@ -1943,8 +2146,12 @@ test_RouteHandler_getAResponseExpr | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:59:37:59:39 | res | | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:59:37:59:39 | res | | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:60:3:60:5 | res | +| src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:60:3:60:12 | [ssa-synth-read] res | +| src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:60:3:60:47 | [ssa-synth-read] res | | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:60:3:60:47 | res.hea ... n/xml") | | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:61:3:61:5 | res | +| src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:61:3:61:10 | [ssa-synth-read] res | +| src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:61:3:61:26 | [ssa-synth-read] res | | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:61:3:61:26 | res.sen ... ms.foo) | | src/express.js:59:23:63:1 | functio ... res);\\n} | src/express.js:62:7:62:9 | res | | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:11:14:11:16 | arg | @@ -1954,8 +2161,12 @@ test_RouteHandler_getAResponseExpr | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:65:41:65:43 | res | | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:65:41:65:43 | res | | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:66:3:66:5 | res | +| src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:66:3:66:12 | [ssa-synth-read] res | +| src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:66:3:66:42 | [ssa-synth-read] res | | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:66:3:66:42 | res.hea ... plain") | | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:67:3:67:5 | res | +| src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:67:3:67:10 | [ssa-synth-read] res | +| src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:67:3:67:26 | [ssa-synth-read] res | | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:67:3:67:26 | res.sen ... ms.foo) | | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:68:7:68:9 | res | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:11:14:11:16 | arg | @@ -1965,13 +2176,19 @@ test_RouteHandler_getAResponseExpr | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:71:37:71:39 | res | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:71:37:71:39 | res | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:72:3:72:5 | res | +| src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:72:3:72:12 | [ssa-synth-read] res | +| src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:72:3:72:41 | [ssa-synth-read] res | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:72:3:72:41 | res.hea ... /html") | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:73:3:73:5 | res | +| src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:73:3:73:10 | [ssa-synth-read] res | +| src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:73:3:73:20 | [ssa-synth-read] res | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:73:3:73:20 | res.send(req.path) | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:74:7:74:9 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:4 | res | +| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:8 | [ssa-synth-read] res | +| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:10 | [ssa-synth-read] res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:6:2:6:4 | res | | src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:37:4:39 | res | | src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:37:4:39 | res | @@ -2009,36 +2226,68 @@ test_RouteHandler_getAResponseExpr | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:14 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:16 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:16 | res.append() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:20:5:20:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:20:5:20:18 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:20:5:20:20 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:20:5:20:20 | res.attachment() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:21:5:21:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:21:5:21:19 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:21:5:21:21 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:21:5:21:21 | res.clearCookie() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:22:5:22:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:22:5:22:19 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:22:5:22:21 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:22:5:22:21 | res.contentType() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:23:5:23:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:23:5:23:14 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:23:5:23:16 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:23:5:23:16 | res.cookie() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:24:5:24:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:24:5:24:14 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:24:5:24:16 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:24:5:24:16 | res.format() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:25:5:25:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:25:5:25:14 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:25:5:25:16 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:25:5:25:16 | res.header() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:26:5:26:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:26:5:26:13 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:26:5:26:15 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:26:5:26:15 | res.links() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:27:5:27:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:27:5:27:16 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:27:5:27:18 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:27:5:27:18 | res.location() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:28:5:28:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:28:5:28:12 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:28:5:28:14 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:28:5:28:14 | res.send() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:29:5:29:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:29:5:29:18 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:29:5:29:20 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:29:5:29:20 | res.sendStatus() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:30:5:30:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:30:5:30:11 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:30:5:30:13 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:30:5:30:13 | res.set() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:31:5:31:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:31:5:31:14 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:31:5:31:16 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:31:5:31:16 | res.status() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:32:5:32:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:32:5:32:12 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:32:5:32:14 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:32:5:32:14 | res.type() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:33:5:33:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:33:5:33:12 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:33:5:33:14 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:33:5:33:14 | res.vary() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:35:5:35:7 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:35:5:35:14 | [ssa-synth-read] res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:35:5:35:16 | [ssa-synth-read] res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:35:5:35:16 | res.status() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:35:5:35:23 | res.status().send() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:37:5:37:19 | f(res.append()) | diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected index 8da9b5087438..a94560e7fff6 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected @@ -9,7 +9,9 @@ test_RequestExpr | src/http.js:4:41:4:43 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:4:41:4:43 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:6:26:6:28 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | +| src/http.js:6:26:6:32 | [ssa-synth-read] req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:8:3:8:5 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | +| src/http.js:8:3:8:13 | [ssa-synth-read] req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:9:3:9:5 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:12:28:12:30 | req | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:55:21:55:23 | req | src/http.js:55:12:55:30 | function(req,res){} | @@ -27,18 +29,22 @@ test_RequestExpr | src/https.js:4:42:4:44 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:4:42:4:44 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:6:26:6:28 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | +| src/https.js:6:26:6:32 | [ssa-synth-read] req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:8:3:8:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | +| src/https.js:8:3:8:13 | [ssa-synth-read] req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:9:3:9:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:12:29:12:31 | req | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/indirect2.js:9:14:9:16 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:9:14:9:16 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:10:12:10:14 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | +| src/indirect2.js:10:12:10:21 | [ssa-synth-read] req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:10:42:10:44 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:13:28:13:30 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:13:28:13:30 | req | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect.js:16:21:16:23 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:16:21:16:23 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:17:28:17:30 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | +| src/indirect.js:17:28:17:34 | [ssa-synth-read] req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:19:33:19:35 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:25:25:25:27 | req | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | | src/indirect.js:28:24:28:26 | req | src/indirect.js:28:15:30:3 | functio ... ");\\n } | @@ -58,13 +64,19 @@ test_ResponseExpr | src/http.js:12:33:12:35 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:12:33:12:35 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:13:3:13:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | +| src/http.js:13:3:13:15 | [ssa-synth-read] res | src/http.js:12:19:16:1 | functio ... ar");\\n} | +| src/http.js:13:3:13:44 | [ssa-synth-read] res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:14:3:14:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | +| src/http.js:14:3:14:11 | [ssa-synth-read] res | src/http.js:12:19:16:1 | functio ... ar");\\n} | +| src/http.js:14:3:14:18 | [ssa-synth-read] res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:15:3:15:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:55:25:55:27 | res | src/http.js:55:12:55:30 | function(req,res){} | | src/http.js:60:27:60:29 | res | src/http.js:60:14:60:32 | function(req,res){} | | src/http.js:62:33:62:35 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:62:33:62:35 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:63:3:63:5 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | +| src/http.js:63:3:63:15 | [ssa-synth-read] res | src/http.js:62:19:65:1 | functio ... r2");\\n} | +| src/http.js:63:3:63:40 | [ssa-synth-read] res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:64:3:64:5 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:68:17:68:19 | res | src/http.js:68:12:68:27 | (req,res) => f() | | src/http.js:72:34:72:36 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | @@ -84,7 +96,11 @@ test_ResponseExpr | src/https.js:12:34:12:36 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:12:34:12:36 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:13:3:13:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | +| src/https.js:13:3:13:15 | [ssa-synth-read] res | src/https.js:12:20:16:1 | functio ... ar");\\n} | +| src/https.js:13:3:13:44 | [ssa-synth-read] res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:14:3:14:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | +| src/https.js:14:3:14:11 | [ssa-synth-read] res | src/https.js:12:20:16:1 | functio ... ar");\\n} | +| src/https.js:14:3:14:18 | [ssa-synth-read] res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:15:3:15:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/indirect2.js:9:19:9:21 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:9:19:9:21 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | @@ -95,6 +111,10 @@ test_ResponseExpr | src/indirect2.js:13:33:13:35 | res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect2.js:14:3:14:5 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:14:3:14:5 | res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | +| src/indirect2.js:14:3:14:15 | [ssa-synth-read] res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | +| src/indirect2.js:14:3:14:15 | [ssa-synth-read] res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | +| src/indirect2.js:14:3:14:51 | [ssa-synth-read] res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | +| src/indirect2.js:14:3:14:51 | [ssa-synth-read] res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect2.js:15:3:15:5 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:15:3:15:5 | res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect.js:16:26:16:28 | res | src/indirect.js:16:12:20:5 | functio ... ;\\n } | @@ -285,7 +305,9 @@ test_RouteHandler_getARequestExpr | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:41:4:43 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:41:4:43 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:6:26:6:28 | req | +| src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:6:26:6:32 | [ssa-synth-read] req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:8:3:8:5 | req | +| src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:8:3:8:13 | [ssa-synth-read] req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:9:3:9:5 | req | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:12:28:12:30 | req | | src/http.js:55:12:55:30 | function(req,res){} | src/http.js:55:21:55:23 | req | @@ -303,18 +325,22 @@ test_RouteHandler_getARequestExpr | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:42:4:44 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:42:4:44 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:6:26:6:28 | req | +| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:6:26:6:32 | [ssa-synth-read] req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:8:3:8:5 | req | +| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:8:3:8:13 | [ssa-synth-read] req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:9:3:9:5 | req | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:29:12:31 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:14:9:16 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:14:9:16 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:10:12:10:14 | req | +| src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:10:12:10:21 | [ssa-synth-read] req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:10:42:10:44 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:13:28:13:30 | req | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:13:28:13:30 | req | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:21:16:23 | req | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:21:16:23 | req | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:17:28:17:30 | req | +| src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:17:28:17:34 | [ssa-synth-read] req | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:19:33:19:35 | req | | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | src/indirect.js:25:25:25:27 | req | | src/indirect.js:28:15:30:3 | functio ... ");\\n } | src/indirect.js:28:24:28:26 | req | @@ -331,13 +357,19 @@ test_RouteHandler_getAResponseExpr | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:12:33:12:35 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:12:33:12:35 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:13:3:13:5 | res | +| src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:13:3:13:15 | [ssa-synth-read] res | +| src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:13:3:13:44 | [ssa-synth-read] res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:14:3:14:5 | res | +| src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:14:3:14:11 | [ssa-synth-read] res | +| src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:14:3:14:18 | [ssa-synth-read] res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:15:3:15:5 | res | | src/http.js:55:12:55:30 | function(req,res){} | src/http.js:55:25:55:27 | res | | src/http.js:60:14:60:32 | function(req,res){} | src/http.js:60:27:60:29 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:33:62:35 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:33:62:35 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:63:3:63:5 | res | +| src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:63:3:63:15 | [ssa-synth-read] res | +| src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:63:3:63:40 | [ssa-synth-read] res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:64:3:64:5 | res | | src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:17:68:19 | res | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:34:72:36 | res | @@ -357,7 +389,11 @@ test_RouteHandler_getAResponseExpr | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:34:12:36 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:34:12:36 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:13:3:13:5 | res | +| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:13:3:13:15 | [ssa-synth-read] res | +| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:13:3:13:44 | [ssa-synth-read] res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:14:3:14:5 | res | +| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:14:3:14:11 | [ssa-synth-read] res | +| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:14:3:14:18 | [ssa-synth-read] res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:15:3:15:5 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:19:9:21 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:19:9:21 | res | @@ -365,10 +401,14 @@ test_RouteHandler_getAResponseExpr | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:13:33:13:35 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:13:33:13:35 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:14:3:14:5 | res | +| src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:14:3:14:15 | [ssa-synth-read] res | +| src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:14:3:14:51 | [ssa-synth-read] res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:15:3:15:5 | res | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:13:33:13:35 | res | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:13:33:13:35 | res | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:14:3:14:5 | res | +| src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:14:3:14:15 | [ssa-synth-read] res | +| src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:14:3:14:51 | [ssa-synth-read] res | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:15:3:15:5 | res | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:26:16:28 | res | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:26:16:28 | res | diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected index 16d31cd07e15..34f708288a84 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected @@ -175,38 +175,52 @@ reactComponentRef | es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | | es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:3:11:3:10 | this | | es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:4:24:4:27 | this | +| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:4:24:4:33 | [ssa-synth-read] this | | es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:6:20:6:19 | this | | es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | | es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:19:11:19:10 | this | | es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:20:24:20:27 | this | +| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:20:24:20:33 | [ssa-synth-read] this | +| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | [ssa-synth-read] this | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | implicit 'this' | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | this | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:2:9:2:8 | this | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:3:24:3:27 | this | +| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:3:24:3:33 | [ssa-synth-read] this | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:5:14:5:13 | this | | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:15:16:15:15 | this | | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:16:9:16:12 | this | +| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:16:9:16:18 | [ssa-synth-read] this | | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:17:9:17:12 | this | +| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:17:9:17:18 | [ssa-synth-read] this | | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:12 | this | +| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:31 | [ssa-synth-read] this | | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | exportedComponent.jsx:1:8:1:7 | this | | importedComponent.jsx:3:8:5:1 | functio ... Value\\n} | importedComponent.jsx:3:8:3:7 | this | +| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | [ssa-synth-read] this | | namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | implicit 'this' | | namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | this | +| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | [ssa-synth-read] this | | namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | implicit 'this' | | namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | this | | plainfn.js:1:1:3:1 | functio ... div>;\\n} | plainfn.js:1:1:1:0 | this | | plainfn.js:5:1:7:1 | functio ... iv");\\n} | plainfn.js:5:1:5:0 | this | | plainfn.js:9:1:12:1 | functio ... rn x;\\n} | plainfn.js:9:1:9:0 | this | | plainfn.js:20:1:24:1 | functio ... n 42;\\n} | plainfn.js:20:1:20:0 | this | +| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | [ssa-synth-read] this | | preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | implicit 'this' | | preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | this | | preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:11:2:10 | this | +| preact.js:9:1:11:1 | class H ... nput\\n\\n} | preact.js:9:38:9:37 | [ssa-synth-read] this | | preact.js:9:1:11:1 | class H ... nput\\n\\n} | preact.js:9:38:9:37 | implicit 'this' | | preact.js:9:1:11:1 | class H ... nput\\n\\n} | preact.js:9:38:9:37 | this | +| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | [ssa-synth-read] this | | probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | implicit 'this' | | probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | this | | probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:2:11:2:10 | this | | probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:3:9:3:12 | this | +| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:3:9:3:18 | [ssa-synth-read] this | +| props.js:2:5:3:5 | class C ... t\\n } | props.js:2:37:2:36 | [ssa-synth-read] this | | props.js:2:5:3:5 | class C ... t\\n } | props.js:2:37:2:36 | implicit 'this' | | props.js:2:5:3:5 | class C ... t\\n } | props.js:2:37:2:36 | this | | props.js:2:5:3:5 | class C ... t\\n } | props.js:9:5:9:55 | new C({ ... ctor"}) | @@ -214,6 +228,7 @@ reactComponentRef | props.js:13:31:17:5 | {\\n ... }\\n } | props.js:14:24:14:23 | this | | props.js:26:5:28:5 | functio ... ;\\n } | props.js:26:5:26:4 | this | | props.js:26:5:28:5 | functio ... ;\\n } | props.js:34:5:34:55 | new C({ ... ctor"}) | +| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | [ssa-synth-read] this | | rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | implicit 'this' | | rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | this | | rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:2:36:2:35 | this | @@ -221,29 +236,42 @@ reactComponentRef | rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:8:28:8:27 | this | | statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:2:16:2:15 | this | | statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:3:9:3:12 | this | +| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:3:9:3:18 | [ssa-synth-read] this | | statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:5:9:5:12 | this | +| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:5:9:5:18 | [ssa-synth-read] this | | statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:9:7:12 | this | +| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:9:7:21 | [ssa-synth-read] this | +| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:9:7:57 | [ssa-synth-read] this | | statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:10:23:10:22 | this | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:2:16:2:15 | this | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:3:13:3:15 | cmp | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:3:19:3:22 | this | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:4:9:4:11 | cmp | +| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:4:9:4:17 | [ssa-synth-read] cmp | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:6:9:6:11 | cmp | +| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:6:9:6:17 | [ssa-synth-read] cmp | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:10:9:10:11 | cmp | +| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:10:9:10:22 | [ssa-synth-read] cmp | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:14:9:14:11 | cmp | +| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:14:9:14:20 | [ssa-synth-read] cmp | +| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:14:9:14:24 | [ssa-synth-read] cmp | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:18:9:18:11 | cmp | +| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:18:9:18:20 | [ssa-synth-read] cmp | +| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:18:9:18:30 | [ssa-synth-read] cmp | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:22:9:22:11 | cmp | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:25:20:25:19 | this | | statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:31:5:33:6 | implicit 'this' | | statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | | statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:37:11:37:10 | this | | statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:38:24:38:27 | this | +| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:38:24:38:33 | [ssa-synth-read] this | | statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:40:20:40:19 | this | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:2:17:2:16 | this | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:3:9:3:12 | this | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:5:13:5:15 | dis | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:5:19:5:22 | this | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:6:9:6:11 | dis | +| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:8:9:10:21 | [ssa-synth-read] this | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:8:10:8:9 | this | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:9:13:9:16 | this | | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:10:17:10:20 | this | @@ -251,32 +279,41 @@ reactComponentRef | thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:14:9:14:12 | this | | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:19:13:19:12 | this | +| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:20:9:22:21 | [ssa-synth-read] this | | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:20:10:20:9 | this | | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:21:13:21:16 | this | | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:22:17:22:20 | this | | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:26:25:26:24 | this | | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:27:9:27:12 | this | | thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:31:2:31:1 | this | +| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:32:5:34:17 | [ssa-synth-read] this | | thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:32:6:32:5 | this | | thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:33:9:33:12 | this | | thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:34:13:34:16 | this | | thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | | thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:39:13:39:12 | this | +| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:40:9:42:16 | [ssa-synth-read] this | | thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:40:38:40:37 | this | | thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:41:13:41:16 | this | | thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:42:12:42:15 | this | | thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:48:17:48:16 | this | | thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:49:9:49:12 | this | +| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:49:9:49:22 | [ssa-synth-read] this | | thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:50:9:50:12 | this | +| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:50:9:50:22 | [ssa-synth-read] this | | thisAccesses.js:54:1:63:1 | class C ... }\\n} | thisAccesses.js:55:16:55:15 | this | | thisAccesses.js:54:1:63:1 | class C ... }\\n} | thisAccesses.js:59:11:59:10 | this | | thisAccesses.js:54:1:63:1 | class C ... }\\n} | thisAccesses.js:60:20:60:23 | this | +| thisAccesses.js:54:1:63:1 | class C ... }\\n} | thisAccesses.js:60:20:60:28 | [ssa-synth-read] this | | thisAccesses.js:54:1:63:1 | class C ... }\\n} | thisAccesses.js:61:20:61:23 | this | +| thisAccesses.js:54:1:63:1 | class C ... }\\n} | thisAccesses.js:61:20:61:28 | [ssa-synth-read] this | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:5:13:5:12 | this | +| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:6:9:8:16 | [ssa-synth-read] this | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:6:38:6:37 | this | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:7:13:7:16 | this | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:8:12:8:15 | this | +| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:9:9:11:16 | [ssa-synth-read] this | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:9:25:9:24 | this | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:10:13:10:16 | this | | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:11:12:11:15 | this | diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected index e2b3b303a6ea..e87d73cb4214 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -105,28 +105,39 @@ test_RouteHandler_getARequestExpr | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:34:26:34:32 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:34:26:34:32 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:17 | [ssa-synth-read] request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:16 | [ssa-synth-read] request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:18 | [ssa-synth-read] request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:54:26:54:32 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:54:26:54:32 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:55:5:55:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:55:5:55:17 | [ssa-synth-read] request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:56:5:56:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:56:5:56:16 | [ssa-synth-read] request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:57:5:57:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:65:26:65:32 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:65:26:65:32 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:66:5:66:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:66:5:66:17 | [ssa-synth-read] request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:67:5:67:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:67:5:67:16 | [ssa-synth-read] request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:68:5:68:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:76:26:76:32 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:76:26:76:32 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:77:5:77:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:77:5:77:17 | [ssa-synth-read] request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:78:5:78:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:78:5:78:16 | [ssa-synth-read] request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:79:5:79:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:87:26:87:32 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:87:26:87:32 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:88:5:88:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:88:5:88:17 | [ssa-synth-read] request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:89:5:89:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:89:5:89:16 | [ssa-synth-read] request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:90:5:90:11 | request | | src/fastify.js:99:17:101:3 | (reques ... nse\\n } | src/fastify.js:99:18:99:24 | request | test_HeaderDefinition_getAHeaderName diff --git a/javascript/ql/test/library-tests/frameworks/hapi/tests.expected b/javascript/ql/test/library-tests/frameworks/hapi/tests.expected index 6d53a86165f8..6b1ef45f9661 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/hapi/tests.expected @@ -23,14 +23,20 @@ test_RequestExpr | src/hapi.js:20:19:20:25 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:20:19:20:25 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:21:3:21:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:21:3:21:20 | [ssa-synth-read] request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:22:3:22:21 | [ssa-synth-read] request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:22:3:22:21 | getRequest(request) | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:22:14:22:20 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:23:3:23:21 | [ssa-synth-read] request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:23:3:23:21 | getRequest(request) | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:23:14:23:20 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:23:34:23:52 | [ssa-synth-read] request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:23:34:23:52 | getRequest(request) | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:23:45:23:51 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:24:3:24:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:24:3:24:13 | [ssa-synth-read] request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:25:3:25:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:25:3:25:17 | [ssa-synth-read] request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:26:3:26:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:34:22:34:24 | req | src/hapi.js:34:12:34:30 | function (req, h){} | | src/hapi.js:38:1:40:1 | return of function getRequest | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | @@ -44,12 +50,19 @@ test_RequestExpr | src/hapiglue.js:20:19:20:25 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:20:19:20:25 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:21:3:21:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | +| src/hapiglue.js:21:3:21:20 | [ssa-synth-read] request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:22:3:22:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | +| src/hapiglue.js:22:3:22:17 | [ssa-synth-read] request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:23:3:23:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | +| src/hapiglue.js:23:3:23:15 | [ssa-synth-read] request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:24:3:24:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | +| src/hapiglue.js:24:3:24:16 | [ssa-synth-read] request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:25:3:25:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | +| src/hapiglue.js:25:3:25:13 | [ssa-synth-read] request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:26:3:26:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | +| src/hapiglue.js:26:3:26:13 | [ssa-synth-read] request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:27:3:27:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | +| src/hapiglue.js:27:3:27:17 | [ssa-synth-read] request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:28:3:28:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | | src/hapiglue.js:36:22:36:24 | req | src/hapiglue.js:36:12:36:33 | functio ... hapi){} | | src/hapihapi.js:13:32:13:38 | request | src/hapihapi.js:13:14:15:5 | functio ... n\\n } | @@ -59,16 +72,23 @@ test_RequestExpr | src/hapihapi.js:20:19:20:25 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:20:19:20:25 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:21:3:21:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapihapi.js:21:3:21:20 | [ssa-synth-read] request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:22:3:22:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapihapi.js:22:3:22:17 | [ssa-synth-read] request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:23:3:23:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapihapi.js:23:3:23:15 | [ssa-synth-read] request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:24:3:24:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapihapi.js:24:3:24:13 | [ssa-synth-read] request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:25:3:25:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapihapi.js:25:3:25:17 | [ssa-synth-read] request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:26:3:26:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapihapi.js:34:22:34:24 | req | src/hapihapi.js:34:12:34:30 | function (req, h){} | | src/wrapped-route-configurator.js:8:39:8:45 | request | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | | src/wrapped-route-configurator.js:8:39:8:45 | request | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | | src/wrapped-route-configurator.js:9:20:9:26 | request | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | +| src/wrapped-route-configurator.js:9:20:9:33 | [ssa-synth-read] request | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | | src/wrapped-route-configurator.js:9:36:9:42 | request | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | +| src/wrapped-route-configurator.js:9:36:9:48 | [ssa-synth-read] request | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | | src/wrapped-route-configurator.js:9:51:9:57 | request | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | test_HeaderAccess | src/hapi.js:25:3:25:21 | request.headers.baz | baz | @@ -186,14 +206,20 @@ test_RouteHandler_getARequestExpr | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:20:19:20:25 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:20:19:20:25 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:21:3:21:9 | request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:21:3:21:20 | [ssa-synth-read] request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:22:3:22:21 | [ssa-synth-read] request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:22:3:22:21 | getRequest(request) | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:22:14:22:20 | request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:3:23:21 | [ssa-synth-read] request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:3:23:21 | getRequest(request) | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:14:23:20 | request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:34:23:52 | [ssa-synth-read] request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:34:23:52 | getRequest(request) | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:45:23:51 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:24:3:24:9 | request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:24:3:24:13 | [ssa-synth-read] request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:25:3:25:9 | request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:25:3:25:17 | [ssa-synth-read] request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:26:3:26:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:38:1:40:1 | return of function getRequest | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:38:21:38:27 | request | @@ -207,12 +233,19 @@ test_RouteHandler_getARequestExpr | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:20:19:20:25 | request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:20:19:20:25 | request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:21:3:21:9 | request | +| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:21:3:21:20 | [ssa-synth-read] request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:22:3:22:9 | request | +| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:22:3:22:17 | [ssa-synth-read] request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:23:3:23:9 | request | +| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:23:3:23:15 | [ssa-synth-read] request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:24:3:24:9 | request | +| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:24:3:24:16 | [ssa-synth-read] request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:25:3:25:9 | request | +| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:25:3:25:13 | [ssa-synth-read] request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:26:3:26:9 | request | +| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:26:3:26:13 | [ssa-synth-read] request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:27:3:27:9 | request | +| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:27:3:27:17 | [ssa-synth-read] request | | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:28:3:28:9 | request | | src/hapiglue.js:36:12:36:33 | functio ... hapi){} | src/hapiglue.js:36:22:36:24 | req | | src/hapihapi.js:13:14:15:5 | functio ... n\\n } | src/hapihapi.js:13:32:13:38 | request | @@ -222,16 +255,23 @@ test_RouteHandler_getARequestExpr | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:20:19:20:25 | request | | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:20:19:20:25 | request | | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:21:3:21:9 | request | +| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:21:3:21:20 | [ssa-synth-read] request | | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:22:3:22:9 | request | +| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:22:3:22:17 | [ssa-synth-read] request | | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:23:3:23:9 | request | +| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:23:3:23:15 | [ssa-synth-read] request | | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:24:3:24:9 | request | +| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:24:3:24:13 | [ssa-synth-read] request | | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:25:3:25:9 | request | +| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:25:3:25:17 | [ssa-synth-read] request | | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:26:3:26:9 | request | | src/hapihapi.js:34:12:34:30 | function (req, h){} | src/hapihapi.js:34:22:34:24 | req | | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | src/wrapped-route-configurator.js:8:39:8:45 | request | | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | src/wrapped-route-configurator.js:8:39:8:45 | request | | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | src/wrapped-route-configurator.js:9:20:9:26 | request | +| src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | src/wrapped-route-configurator.js:9:20:9:33 | [ssa-synth-read] request | | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | src/wrapped-route-configurator.js:9:36:9:42 | request | +| src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | src/wrapped-route-configurator.js:9:36:9:48 | [ssa-synth-read] request | | src/wrapped-route-configurator.js:8:23:10:3 | async f ... d);\\n } | src/wrapped-route-configurator.js:9:51:9:57 | request | test_HeaderDefinition_getAHeaderName | src/hapi.js:14:9:14:46 | request ... 1', '') | header1 | diff --git a/javascript/ql/test/library-tests/frameworks/koa/tests.expected b/javascript/ql/test/library-tests/frameworks/koa/tests.expected index 1c3a323d1105..570be491613d 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/koa/tests.expected @@ -10,42 +10,76 @@ test_ContextExpr | src/koa.js:10:28:10:30 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:10:28:10:30 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:11:3:11:6 | this | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:11:3:11:10 | [ssa-synth-read] this | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:11:3:11:25 | [ssa-synth-read] this | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:12:3:12:6 | this | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:12:3:12:15 | [ssa-synth-read] this | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:13:3:13:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:13:3:13:9 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:13:3:13:24 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:14:3:14:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:14:3:14:14 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:15:13:15:15 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:15:13:15:24 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:18:3:18:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:18:3:18:14 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:19:3:19:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:19:3:19:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:20:3:20:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:20:3:20:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:21:3:21:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:21:3:21:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:22:3:22:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:22:3:22:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:23:3:23:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:23:3:23:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:24:3:24:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:24:3:24:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:25:3:25:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:25:3:25:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:26:3:26:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:26:3:26:13 | [ssa-synth-read] ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:27:3:27:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:30:16:30:18 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:30:16:30:18 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:31:2:31:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:31:2:31:13 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:32:2:32:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:32:2:32:9 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:33:2:33:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:33:2:33:10 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:34:2:34:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:34:2:34:8 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:35:2:35:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:35:2:35:16 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:36:2:36:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:36:2:36:9 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:37:2:37:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:37:2:37:11 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:38:2:38:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:38:2:38:12 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:39:2:39:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:39:2:39:8 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:39:2:39:15 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:40:2:40:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:40:2:40:8 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:40:2:40:15 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:42:12:42:14 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:42:12:42:20 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:43:2:43:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:43:2:43:13 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:43:2:43:18 | [ssa-synth-read] ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:44:2:44:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:47:16:47:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:47:16:47:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:48:16:48:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | +| src/koa.js:48:16:48:26 | [ssa-synth-read] ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:51:14:51:16 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | +| src/koa.js:51:14:51:22 | [ssa-synth-read] ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:54:16:54:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:59:10:59:9 | this | src/koa.js:59:10:61:1 | functio ... .url;\\n} | | src/koa.js:60:2:60:5 | this | src/koa.js:59:10:61:1 | functio ... .url;\\n} | +| src/koa.js:60:2:60:13 | [ssa-synth-read] this | src/koa.js:59:10:61:1 | functio ... .url;\\n} | test_RequestExpr | src/koa.js:19:3:19:13 | ctx.request | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:20:3:20:13 | ctx.request | src/koa.js:10:10:28:1 | functio ... az');\\n} | @@ -141,42 +175,76 @@ test_RouteHandler_getAContextExpr | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:10:28:10:30 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:10:28:10:30 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:11:3:11:6 | this | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:11:3:11:10 | [ssa-synth-read] this | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:11:3:11:25 | [ssa-synth-read] this | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:12:3:12:6 | this | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:12:3:12:15 | [ssa-synth-read] this | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:13:3:13:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:13:3:13:9 | [ssa-synth-read] ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:13:3:13:24 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:14:3:14:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:14:3:14:14 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:15:13:15:15 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:15:13:15:24 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:18:3:18:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:18:3:18:14 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:19:3:19:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:19:3:19:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:20:3:20:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:20:3:20:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:21:3:21:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:21:3:21:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:22:3:22:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:22:3:22:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:23:3:23:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:23:3:23:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:24:3:24:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:24:3:24:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:25:3:25:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:25:3:25:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:26:3:26:5 | ctx | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:26:3:26:13 | [ssa-synth-read] ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:27:3:27:5 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:30:16:30:18 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:30:16:30:18 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:31:2:31:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:31:2:31:13 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:32:2:32:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:32:2:32:9 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:33:2:33:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:33:2:33:10 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:34:2:34:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:34:2:34:8 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:35:2:35:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:35:2:35:16 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:36:2:36:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:36:2:36:9 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:37:2:37:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:37:2:37:11 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:38:2:38:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:38:2:38:12 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:39:2:39:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:39:2:39:8 | [ssa-synth-read] ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:39:2:39:15 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:40:2:40:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:40:2:40:8 | [ssa-synth-read] ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:40:2:40:15 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:42:12:42:14 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:42:12:42:20 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:43:2:43:4 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:43:2:43:13 | [ssa-synth-read] ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:43:2:43:18 | [ssa-synth-read] ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:44:2:44:4 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:47:16:47:18 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:47:16:47:18 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:48:16:48:18 | ctx | +| src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:48:16:48:26 | [ssa-synth-read] ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:51:14:51:16 | ctx | +| src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:51:14:51:22 | [ssa-synth-read] ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:54:16:54:18 | ctx | | src/koa.js:59:10:61:1 | functio ... .url;\\n} | src/koa.js:59:10:59:9 | this | | src/koa.js:59:10:61:1 | functio ... .url;\\n} | src/koa.js:60:2:60:5 | this | +| src/koa.js:59:10:61:1 | functio ... .url;\\n} | src/koa.js:60:2:60:13 | [ssa-synth-read] this | test_RouteHandler_getARequestExpr | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:19:3:19:13 | ctx.request | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:20:3:20:13 | ctx.request | diff --git a/javascript/ql/test/library-tests/frameworks/restify/tests.expected b/javascript/ql/test/library-tests/frameworks/restify/tests.expected index 7cc5f1a2770d..aebac4192988 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/restify/tests.expected @@ -7,12 +7,26 @@ test_RequestExpr | src/test.js:12:37:12:43 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:12:37:12:43 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:14:5:14:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:14:5:14:20 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:14:5:14:22 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:15:5:15:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:15:5:15:16 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:15:5:15:18 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:16:5:16:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:16:5:16:19 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:16:5:16:21 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:17:5:17:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:17:5:17:26 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:17:5:17:28 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:18:5:18:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:18:5:18:21 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:18:5:18:23 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:19:5:19:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:19:5:19:19 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:19:5:19:26 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:20:5:20:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:20:5:20:18 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:20:5:20:25 | [ssa-synth-read] request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:21:5:21:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | test_ResponseExpr | src/test.js:9:46:9:53 | response | src/test.js:9:19:11:1 | functio ... ition\\n} | @@ -61,12 +75,26 @@ test_RouteHandler_getARequestExpr | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:37:12:43 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:37:12:43 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:14:5:14:11 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:14:5:14:20 | [ssa-synth-read] request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:14:5:14:22 | [ssa-synth-read] request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:15:5:15:11 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:15:5:15:16 | [ssa-synth-read] request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:15:5:15:18 | [ssa-synth-read] request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:16:5:16:11 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:16:5:16:19 | [ssa-synth-read] request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:16:5:16:21 | [ssa-synth-read] request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:17:5:17:11 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:17:5:17:26 | [ssa-synth-read] request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:17:5:17:28 | [ssa-synth-read] request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:18:5:18:11 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:18:5:18:21 | [ssa-synth-read] request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:18:5:18:23 | [ssa-synth-read] request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:19:5:19:11 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:19:5:19:19 | [ssa-synth-read] request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:19:5:19:26 | [ssa-synth-read] request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:20:5:20:11 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:20:5:20:18 | [ssa-synth-read] request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:20:5:20:25 | [ssa-synth-read] request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:21:5:21:11 | request | test_RouteHandler_getAResponseExpr | src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:9:46:9:53 | response | 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 3f854c95b7d8..a1082b3f58fa 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 @@ -127,7 +127,6 @@ | normalizedPaths.js:194:21:194:24 | path | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:194:21:194:24 | path | This path depends on a $@. | normalizedPaths.js:174:14:174:27 | req.query.path | user-provided value | | normalizedPaths.js:199:21:199:24 | path | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:199:21:199:24 | path | This path depends on a $@. | normalizedPaths.js:174:14:174:27 | req.query.path | user-provided value | | normalizedPaths.js:205:21:205:34 | normalizedPath | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:205:21:205:34 | normalizedPath | This path depends on a $@. | normalizedPaths.js:174:14:174:27 | req.query.path | user-provided value | -| normalizedPaths.js:208:21:208:34 | normalizedPath | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:208:21:208:34 | normalizedPath | This path depends on a $@. | normalizedPaths.js:174:14:174:27 | req.query.path | user-provided value | | normalizedPaths.js:210:21:210:34 | normalizedPath | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:210:21:210:34 | normalizedPath | This path depends on a $@. | normalizedPaths.js:174:14:174:27 | req.query.path | user-provided value | | normalizedPaths.js:222:21:222:24 | path | normalizedPaths.js:214:35:214:48 | req.query.path | normalizedPaths.js:222:21:222:24 | path | This path depends on a $@. | normalizedPaths.js:214:35:214:48 | req.query.path | user-provided value | | normalizedPaths.js:228:21:228:24 | path | normalizedPaths.js:226:35:226:48 | req.query.path | normalizedPaths.js:228:21:228:24 | path | This path depends on a $@. | normalizedPaths.js:226:35:226:48 | req.query.path | user-provided value | @@ -535,7 +534,6 @@ edges | normalizedPaths.js:174:7:174:10 | path | normalizedPaths.js:201:45:201:48 | path | provenance | | | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:174:7:174:10 | path | provenance | | | normalizedPaths.js:201:7:201:20 | normalizedPath | normalizedPaths.js:205:21:205:34 | normalizedPath | provenance | | -| normalizedPaths.js:201:7:201:20 | normalizedPath | normalizedPaths.js:208:21:208:34 | normalizedPath | provenance | | | normalizedPaths.js:201:7:201:20 | normalizedPath | normalizedPaths.js:210:21:210:34 | normalizedPath | provenance | | | normalizedPaths.js:201:24:201:49 | pathMod ... e(path) | normalizedPaths.js:201:7:201:20 | normalizedPath | provenance | | | normalizedPaths.js:201:45:201:48 | path | normalizedPaths.js:201:24:201:49 | pathMod ... e(path) | provenance | Config | @@ -1116,7 +1114,6 @@ nodes | normalizedPaths.js:201:24:201:49 | pathMod ... e(path) | semmle.label | pathMod ... e(path) | | normalizedPaths.js:201:45:201:48 | path | semmle.label | path | | normalizedPaths.js:205:21:205:34 | normalizedPath | semmle.label | normalizedPath | -| normalizedPaths.js:208:21:208:34 | normalizedPath | semmle.label | normalizedPath | | normalizedPaths.js:210:21:210:34 | normalizedPath | semmle.label | normalizedPath | | normalizedPaths.js:214:7:214:10 | path | semmle.label | path | | normalizedPaths.js:214:14:214:49 | pathMod ... y.path) | semmle.label | pathMod ... y.path) | 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 4365de77a40f..8588ffbb1eae 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 @@ -205,7 +205,7 @@ app.get('/join-regression', (req, res) => { fs.readFileSync(normalizedPath); // $ Alert if (normalizedPath.startsWith('/home/user/www') || normalizedPath.startsWith('/home/user/public')) - fs.readFileSync(normalizedPath); // $ SPURIOUS: Alert + fs.readFileSync(normalizedPath); else fs.readFileSync(normalizedPath); // $ Alert }); diff --git a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected index 5da2f2819639..21435b065827 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/SecondOrderCommandInjection.expected @@ -3,7 +3,6 @@ | second-order.js:9:29:9:34 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:9:29:9:34 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value | | second-order.js:11:33:11:38 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:11:33:11:38 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value | | second-order.js:15:19:15:24 | myArgs | second-order.js:13:18:13:31 | req.query.args | second-order.js:15:19:15:24 | myArgs | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:13:18:13:31 | req.query.args | a user-provided value | -| second-order.js:23:33:23:38 | remote | second-order.js:6:18:6:33 | req.query.remote | second-order.js:23:33:23:38 | remote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:6:18:6:33 | req.query.remote | a user-provided value | | second-order.js:29:35:29:49 | uncheckedRemote | second-order.js:25:27:25:51 | req.que ... dRemote | second-order.js:29:35:29:49 | uncheckedRemote | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:25:27:25:51 | req.que ... dRemote | a user-provided value | | second-order.js:32:19:32:32 | req.query.args | second-order.js:32:19:32:32 | req.query.args | second-order.js:32:19:32:32 | req.query.args | Command line argument that depends on $@ can execute an arbitrary command if --upload-pack is used with git. | second-order.js:32:19:32:32 | req.query.args | a user-provided value | | second-order.js:43:28:43:43 | req.query.remote | second-order.js:43:28:43:43 | req.query.remote | second-order.js:43:28:43:43 | req.query.remote | Command line argument that depends on $@ can execute an arbitrary command if --config=alias.= is used with hg. | second-order.js:43:28:43:43 | req.query.remote | a user-provided value | @@ -13,7 +12,6 @@ edges | second-order.js:6:9:6:14 | remote | second-order.js:7:33:7:38 | remote | provenance | | | second-order.js:6:9:6:14 | remote | second-order.js:9:29:9:34 | remote | provenance | | | second-order.js:6:9:6:14 | remote | second-order.js:11:33:11:38 | remote | provenance | | -| second-order.js:6:9:6:14 | remote | second-order.js:23:33:23:38 | remote | provenance | | | second-order.js:6:18:6:33 | req.query.remote | second-order.js:6:9:6:14 | remote | provenance | | | second-order.js:13:9:13:14 | myArgs | second-order.js:15:19:15:24 | myArgs | provenance | | | second-order.js:13:18:13:31 | req.query.args | second-order.js:13:9:13:14 | myArgs | provenance | | @@ -28,7 +26,6 @@ nodes | second-order.js:13:9:13:14 | myArgs | semmle.label | myArgs | | second-order.js:13:18:13:31 | req.query.args | semmle.label | req.query.args | | second-order.js:15:19:15:24 | myArgs | semmle.label | myArgs | -| second-order.js:23:33:23:38 | remote | semmle.label | remote | | second-order.js:25:9:25:23 | uncheckedRemote | semmle.label | uncheckedRemote | | second-order.js:25:27:25:51 | req.que ... dRemote | semmle.label | req.que ... dRemote | | second-order.js:29:35:29:49 | uncheckedRemote | semmle.label | uncheckedRemote | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js index 946706c89bcc..4656afd50713 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/SecondOrderCommandInjection/second-order.js @@ -20,7 +20,7 @@ app.get("/", (req, res) => { execFile("git", ["ls-remote", remote, "HEAD"]); // OK - it's not an option } - execFile("git", ["ls-remote", remote, "HEAD"]); // $ SPURIOUS: Alert - both outcomes of the earlier check are modeled as safe. + execFile("git", ["ls-remote", remote, "HEAD"]); // Both outcomes of the earlier check are modeled as safe. const uncheckedRemote = req.query.uncheckedRemote; // $ Source if (uncheckedRemote.startsWith("git@")) { diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected index 564d9ca221e7..c077a32d9218 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected @@ -47,7 +47,6 @@ | lib/lib.js:228:10:228:25 | "rm -rf " + name | lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:227:39:227:42 | name | library input | lib/lib.js:228:2:228:26 | cp.exec ... + name) | shell command | | lib/lib.js:236:10:236:25 | "rm -rf " + name | lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:227:39:227:42 | name | library input | lib/lib.js:236:2:236:26 | cp.exec ... + name) | shell command | | lib/lib.js:249:10:249:25 | "rm -rf " + name | lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:248:42:248:45 | name | library input | lib/lib.js:249:2:249:26 | cp.exec ... + name) | shell command | -| lib/lib.js:253:10:253:28 | "rm -rf " + cleaned | lib/lib.js:248:42:248:45 | name | lib/lib.js:253:22:253:28 | cleaned | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:248:42:248:45 | name | library input | lib/lib.js:253:2:253:29 | cp.exec ... leaned) | shell command | | lib/lib.js:258:10:258:25 | "rm -rf " + name | lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:257:35:257:38 | name | library input | lib/lib.js:258:2:258:26 | cp.exec ... + name) | shell command | | lib/lib.js:261:11:261:33 | "rm -rf ... + name | lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:257:35:257:38 | name | library input | lib/lib.js:261:3:261:34 | cp.exec ... + name) | shell command | | lib/lib.js:268:10:268:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:32 | obj.version | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:267:46:267:48 | obj | library input | lib/lib.js:268:2:268:33 | cp.exec ... ersion) | shell command | @@ -157,13 +156,7 @@ edges | lib/lib.js:216:39:216:42 | name | lib/lib.js:224:22:224:25 | name | provenance | | | lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | provenance | | | lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | provenance | | -| lib/lib.js:239:28:239:28 | s | lib/lib.js:245:9:245:9 | s | provenance | | | lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | provenance | | -| lib/lib.js:248:42:248:45 | name | lib/lib.js:251:27:251:30 | name | provenance | | -| lib/lib.js:251:6:251:12 | cleaned | lib/lib.js:253:22:253:28 | cleaned | provenance | | -| lib/lib.js:251:16:251:31 | cleanInput(name) | lib/lib.js:251:6:251:12 | cleaned | provenance | | -| lib/lib.js:251:27:251:30 | name | lib/lib.js:239:28:239:28 | s | provenance | | -| lib/lib.js:251:27:251:30 | name | lib/lib.js:251:16:251:31 | cleanInput(name) | provenance | | | lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | provenance | | | lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | provenance | | | lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:24 | obj | provenance | | @@ -329,14 +322,8 @@ nodes | lib/lib.js:227:39:227:42 | name | semmle.label | name | | lib/lib.js:228:22:228:25 | name | semmle.label | name | | lib/lib.js:236:22:236:25 | name | semmle.label | name | -| lib/lib.js:239:28:239:28 | s | semmle.label | s | -| lib/lib.js:245:9:245:9 | s | semmle.label | s | | lib/lib.js:248:42:248:45 | name | semmle.label | name | | lib/lib.js:249:22:249:25 | name | semmle.label | name | -| lib/lib.js:251:6:251:12 | cleaned | semmle.label | cleaned | -| lib/lib.js:251:16:251:31 | cleanInput(name) | semmle.label | cleanInput(name) | -| lib/lib.js:251:27:251:30 | name | semmle.label | name | -| lib/lib.js:253:22:253:28 | cleaned | semmle.label | cleaned | | lib/lib.js:257:35:257:38 | name | semmle.label | name | | lib/lib.js:258:22:258:25 | name | semmle.label | name | | lib/lib.js:261:30:261:33 | name | semmle.label | name | @@ -452,6 +439,5 @@ nodes | lib/subLib/index.js:13:44:13:46 | arr | semmle.label | arr | | lib/subLib/index.js:14:22:14:24 | arr | semmle.label | arr | subpaths -| lib/lib.js:251:27:251:30 | name | lib/lib.js:239:28:239:28 | s | lib/lib.js:245:9:245:9 | s | lib/lib.js:251:16:251:31 | cleanInput(name) | | lib/lib.js:340:25:340:25 | n | lib/lib.js:329:13:329:13 | x | lib/lib.js:330:9:330:9 | x | lib/lib.js:340:22:340:26 | id(n) | | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:431:23:431:26 | last | lib/lib.js:437:9:437:11 | arr [ArrayElement] | lib/lib.js:428:14:428:58 | build(" ... + '-') | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js index e7911746d6eb..e6e93b5bc433 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js @@ -250,7 +250,7 @@ module.exports.goodSanitizer = function (name) { // $ Source var cleaned = cleanInput(name); - cp.exec("rm -rf " + cleaned); // $ SPURIOUS: Alert - SanitizingRegExpTest is not able to generate a barrier edge for an edge into a phi node. + cp.exec("rm -rf " + cleaned); } var fs = require("fs"); diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index fce55fec2936..866bc99a2ee3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -702,10 +702,8 @@ edges | tst.js:375:18:375:23 | target [taint3] | tst.js:375:18:375:30 | target.taint3 | provenance | | | tst.js:380:18:380:23 | target | tst.js:380:18:380:30 | target.taint5 | provenance | | | tst.js:389:18:389:23 | target | tst.js:389:18:389:30 | target.taint7 | provenance | | -| tst.js:391:3:391:8 | [post update] target [taint8] | tst.js:391:19:391:24 | target [taint8] | provenance | | | tst.js:391:3:391:8 | [post update] target [taint8] | tst.js:392:18:392:23 | target [taint8] | provenance | | | tst.js:391:19:391:24 | target | tst.js:391:19:391:31 | target.taint8 | provenance | | -| tst.js:391:19:391:24 | target [taint8] | tst.js:391:19:391:31 | target.taint8 | provenance | | | tst.js:391:19:391:31 | target.taint8 | tst.js:391:3:391:8 | [post update] target [taint8] | provenance | | | tst.js:392:18:392:23 | target [taint8] | tst.js:392:18:392:30 | target.taint8 | provenance | | | tst.js:399:7:399:13 | payload | tst.js:400:18:400:24 | payload | provenance | | @@ -1351,7 +1349,6 @@ nodes | tst.js:389:18:389:30 | target.taint7 | semmle.label | target.taint7 | | tst.js:391:3:391:8 | [post update] target [taint8] | semmle.label | [post update] target [taint8] | | tst.js:391:19:391:24 | target | semmle.label | target | -| tst.js:391:19:391:24 | target [taint8] | semmle.label | target [taint8] | | tst.js:391:19:391:31 | target.taint8 | semmle.label | target.taint8 | | tst.js:392:18:392:23 | target [taint8] | semmle.label | target [taint8] | | tst.js:392:18:392:30 | target.taint8 | semmle.label | target.taint8 | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index f8781e6741b9..c508da8aee2a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -658,7 +658,6 @@ nodes | tst.js:389:18:389:30 | target.taint7 | semmle.label | target.taint7 | | tst.js:391:3:391:8 | [post update] target [taint8] | semmle.label | [post update] target [taint8] | | tst.js:391:19:391:24 | target | semmle.label | target | -| tst.js:391:19:391:24 | target [taint8] | semmle.label | target [taint8] | | tst.js:391:19:391:31 | target.taint8 | semmle.label | target.taint8 | | tst.js:392:18:392:23 | target [taint8] | semmle.label | target [taint8] | | tst.js:392:18:392:30 | target.taint8 | semmle.label | target.taint8 | @@ -1302,10 +1301,8 @@ edges | tst.js:375:18:375:23 | target [taint3] | tst.js:375:18:375:30 | target.taint3 | provenance | | | tst.js:380:18:380:23 | target | tst.js:380:18:380:30 | target.taint5 | provenance | | | tst.js:389:18:389:23 | target | tst.js:389:18:389:30 | target.taint7 | provenance | | -| tst.js:391:3:391:8 | [post update] target [taint8] | tst.js:391:19:391:24 | target [taint8] | provenance | | | tst.js:391:3:391:8 | [post update] target [taint8] | tst.js:392:18:392:23 | target [taint8] | provenance | | | tst.js:391:19:391:24 | target | tst.js:391:19:391:31 | target.taint8 | provenance | | -| tst.js:391:19:391:24 | target [taint8] | tst.js:391:19:391:31 | target.taint8 | provenance | | | tst.js:391:19:391:31 | target.taint8 | tst.js:391:3:391:8 | [post update] target [taint8] | provenance | | | tst.js:392:18:392:23 | target [taint8] | tst.js:392:18:392:30 | target.taint8 | provenance | | | tst.js:399:7:399:13 | payload | tst.js:400:18:400:24 | payload | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index 17d280d38096..eac2633114f5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -45,7 +45,6 @@ | json-schema-validator.js:55:22:55:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:55:22:55:26 | query | This query object depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | | json-schema-validator.js:59:22:59:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:59:22:59:26 | query | This query object depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | | json-schema-validator.js:61:22:61:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:61:22:61:26 | query | This query object depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | -| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | koarouter.js:5:13:5:19 | version | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | This query string depends on a $@. | koarouter.js:5:13:5:19 | version | user-provided value | | ldap.js:28:30:28:34 | opts1 | ldap.js:20:21:20:27 | req.url | ldap.js:28:30:28:34 | opts1 | This query string depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | | ldap.js:32:5:32:61 | { filte ... e}))` } | ldap.js:20:21:20:27 | req.url | ldap.js:32:5:32:61 | { filte ... e}))` } | This query string depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | | ldap.js:66:30:66:53 | { filte ... ilter } | ldap.js:20:21:20:27 | req.url | ldap.js:66:30:66:53 | { filte ... ilter } | This query string depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | @@ -302,13 +301,6 @@ edges | json-schema-validator.js:50:15:50:19 | query | json-schema-validator.js:61:22:61:26 | query | provenance | | | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | json-schema-validator.js:50:15:50:19 | query | provenance | | | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | provenance | Config | -| koarouter.js:5:13:5:19 | version | koarouter.js:5:13:5:19 | version | provenance | | -| koarouter.js:5:13:5:19 | version | koarouter.js:14:38:14:44 | version | provenance | | -| koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | koarouter.js:17:52:17:61 | conditions [ArrayElement] | provenance | | -| koarouter.js:14:25:14:46 | `versio ... rsion}` | koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | provenance | | -| koarouter.js:14:38:14:44 | version | koarouter.js:14:25:14:46 | `versio ... rsion}` | provenance | | -| koarouter.js:17:52:17:61 | conditions [ArrayElement] | koarouter.js:17:52:17:75 | conditi ... and ') | provenance | | -| koarouter.js:17:52:17:75 | conditi ... and ') | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | provenance | | | ldap.js:20:7:20:7 | q | ldap.js:22:18:22:18 | q | provenance | | | ldap.js:20:11:20:34 | url.par ... , true) | ldap.js:20:7:20:7 | q | provenance | | | ldap.js:20:21:20:27 | req.url | ldap.js:20:11:20:34 | url.par ... , true) | provenance | | @@ -790,14 +782,6 @@ nodes | json-schema-validator.js:55:22:55:26 | query | semmle.label | query | | json-schema-validator.js:59:22:59:26 | query | semmle.label | query | | json-schema-validator.js:61:22:61:26 | query | semmle.label | query | -| koarouter.js:5:13:5:19 | version | semmle.label | version | -| koarouter.js:5:13:5:19 | version | semmle.label | version | -| koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | semmle.label | [post update] conditions [ArrayElement] | -| koarouter.js:14:25:14:46 | `versio ... rsion}` | semmle.label | `versio ... rsion}` | -| koarouter.js:14:38:14:44 | version | semmle.label | version | -| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | semmle.label | `SELECT ... nd ')}` | -| koarouter.js:17:52:17:61 | conditions [ArrayElement] | semmle.label | conditions [ArrayElement] | -| koarouter.js:17:52:17:75 | conditi ... and ') | semmle.label | conditi ... and ') | | ldap.js:20:7:20:7 | q | semmle.label | q | | ldap.js:20:11:20:34 | url.par ... , true) | semmle.label | url.par ... , true) | | ldap.js:20:21:20:27 | req.url | semmle.label | req.url | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js index 3f7254c9a264..e07fa929063c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js @@ -2,7 +2,7 @@ const Router = require('koa-router') const {Sequelize} = require("sequelize"); new Router().get("/hello", (ctx) => { - const { version } = ctx.query; // $ Source + const { version } = ctx.query; if (version && validVersion(version) === false) { throw new Error(`invalid version ${version}`); @@ -14,7 +14,7 @@ new Router().get("/hello", (ctx) => { conditions.push(`version = ${version}`) } - new Sequelize().query(`SELECT * FROM t WHERE ${conditions.join(' and ')}`, null); // $ Alert + new Sequelize().query(`SELECT * FROM t WHERE ${conditions.join(' and ')}`, null); }); function validVersion(version) { diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected index 7eb7c2fdf90a..eab4dd0ead0e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected @@ -17,7 +17,6 @@ | tests.js:280:13:280:15 | dst | tests.js:276:34:276:36 | key | tests.js:280:13:280:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:276:21:276:23 | src | src | tests.js:280:13:280:15 | dst | dst | | tests.js:308:17:308:19 | dst | tests.js:302:14:302:16 | key | tests.js:308:17:308:19 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:302:21:302:23 | src | src | tests.js:308:17:308:19 | dst | dst | | tests.js:322:17:322:19 | dst | tests.js:315:14:315:16 | key | tests.js:322:17:322:19 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:315:21:315:23 | src | src | tests.js:322:17:322:19 | dst | dst | -| tests.js:338:17:338:19 | dst | tests.js:329:14:329:16 | key | tests.js:338:17:338:19 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:329:21:329:23 | src | src | tests.js:338:17:338:19 | dst | dst | | tests.js:357:17:357:22 | target | tests.js:350:37:350:39 | key | tests.js:357:17:357:22 | target | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:350:21:350:26 | source | source | tests.js:357:17:357:22 | target | target | | tests.js:403:13:403:15 | dst | tests.js:381:14:381:16 | key | tests.js:403:13:403:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:381:21:381:23 | obj | obj | tests.js:403:13:403:15 | dst | dst | | tests.js:419:13:419:15 | dst | tests.js:413:14:413:16 | key | tests.js:419:13:419:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:413:21:413:23 | src | src | tests.js:419:13:419:15 | dst | dst | @@ -396,22 +395,11 @@ edges | tests.js:320:38:320:45 | dst[key] | tests.js:314:31:314:33 | dst | provenance | | | tests.js:320:42:320:44 | key | tests.js:320:38:320:45 | dst[key] | provenance | Config | | tests.js:320:48:320:52 | value | tests.js:314:36:314:38 | src | provenance | | -| tests.js:328:25:328:27 | dst | tests.js:336:32:336:34 | dst | provenance | | -| tests.js:328:25:328:27 | dst | tests.js:338:17:338:19 | dst | provenance | | | tests.js:328:30:328:32 | src | tests.js:336:42:336:44 | src | provenance | | | tests.js:328:30:328:32 | src | tests.js:338:28:338:30 | src | provenance | | -| tests.js:329:14:329:16 | key | tests.js:336:36:336:38 | key | provenance | | -| tests.js:329:14:329:16 | key | tests.js:336:46:336:48 | key | provenance | | -| tests.js:329:14:329:16 | key | tests.js:338:21:338:23 | key | provenance | | -| tests.js:329:14:329:16 | key | tests.js:338:32:338:34 | key | provenance | | -| tests.js:336:32:336:34 | dst | tests.js:336:32:336:39 | dst[key] | provenance | Config | -| tests.js:336:32:336:39 | dst[key] | tests.js:328:25:328:27 | dst | provenance | | -| tests.js:336:36:336:38 | key | tests.js:336:32:336:39 | dst[key] | provenance | Config | | tests.js:336:42:336:44 | src | tests.js:336:42:336:49 | src[key] | provenance | Config | | tests.js:336:42:336:49 | src[key] | tests.js:328:30:328:32 | src | provenance | | -| tests.js:336:46:336:48 | key | tests.js:336:42:336:49 | src[key] | provenance | Config | | tests.js:338:28:338:30 | src | tests.js:338:28:338:35 | src[key] | provenance | Config | -| tests.js:338:32:338:34 | key | tests.js:338:28:338:35 | src[key] | provenance | Config | | tests.js:348:32:348:37 | target | tests.js:349:26:349:31 | target | provenance | | | tests.js:348:32:348:37 | target | tests.js:361:12:361:17 | target | provenance | | | tests.js:348:40:348:45 | source | tests.js:349:54:349:59 | source | provenance | | @@ -1092,20 +1080,11 @@ nodes | tests.js:322:17:322:19 | dst | semmle.label | dst | | tests.js:322:21:322:23 | key | semmle.label | key | | tests.js:322:28:322:32 | value | semmle.label | value | -| tests.js:328:25:328:27 | dst | semmle.label | dst | | tests.js:328:30:328:32 | src | semmle.label | src | -| tests.js:329:14:329:16 | key | semmle.label | key | -| tests.js:336:32:336:34 | dst | semmle.label | dst | -| tests.js:336:32:336:39 | dst[key] | semmle.label | dst[key] | -| tests.js:336:36:336:38 | key | semmle.label | key | | tests.js:336:42:336:44 | src | semmle.label | src | | tests.js:336:42:336:49 | src[key] | semmle.label | src[key] | -| tests.js:336:46:336:48 | key | semmle.label | key | -| tests.js:338:17:338:19 | dst | semmle.label | dst | -| tests.js:338:21:338:23 | key | semmle.label | key | | tests.js:338:28:338:30 | src | semmle.label | src | | tests.js:338:28:338:35 | src[key] | semmle.label | src[key] | -| tests.js:338:32:338:34 | key | semmle.label | key | | tests.js:348:32:348:37 | target | semmle.label | target | | tests.js:348:40:348:45 | source | semmle.label | source | | tests.js:349:26:349:31 | target | semmle.label | target | diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js index dcce195526ac..59c22a974049 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js @@ -326,7 +326,7 @@ function mergeRephinementNode(dst, src) { } function mergeSelective(dst, src) { - for (let key in src) { // $ Source + for (let key in src) { if (src.hasOwnProperty(key)) { // Only 'prefs' is merged recursively if (key in dst && key !== 'prefs') { @@ -335,7 +335,7 @@ function mergeSelective(dst, src) { if (dst[key]) { mergeSelective(dst[key], src[key]); } else { - dst[key] = src[key]; // $ Alert + dst[key] = src[key]; } } }