Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 78e961c

Browse files
committed
JS: Add use-use flow
1 parent 81e74d8 commit 78e961c

3 files changed

Lines changed: 105 additions & 11 deletions

File tree

javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import javascript
88
private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
99
private import semmle.javascript.dataflow.internal.Contents::Private
1010
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
11+
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
1112
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
1213
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
1314
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
@@ -27,7 +28,14 @@ private module Cached {
2728
cached
2829
newtype TNode =
2930
TValueNode(AST::ValueNode nd) or
31+
/** An SSA node from the legacy SSA library */
3032
TSsaDefNode(SsaDefinition d) or
33+
/** Use of a variable with flow from a post-update node (from an earlier use) */
34+
TSsaUseNode(VarUse use) { use.getVariable() instanceof PurelyLocalVariable } or
35+
/** Phi-read node (new SSA library). Ordinary phi nodes are represented by TSsaDefNode. */
36+
TSsaPhiReadNode(Ssa2::PhiReadNode phi) or
37+
/** Input to a phi node (new SSA library) */
38+
TSsaInputNode(Ssa2::SsaInputNode input) or
3139
TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
3240
TPropNode(@property p) or
3341
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or

javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
66
private import semmle.javascript.dataflow.internal.Contents::Private
77
private import semmle.javascript.dataflow.internal.VariableCapture
88
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
9+
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
910
private import semmle.javascript.internal.flow_summaries.AllFlowSummaries
1011
private import sharedlib.FlowSummaryImpl as FlowSummaryImpl
1112
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
@@ -18,6 +19,55 @@ private class Node = DataFlow::Node;
1819

1920
class PostUpdateNode = DataFlow::PostUpdateNode;
2021

22+
class SsaUseNode extends DataFlow::Node, TSsaUseNode {
23+
private VarAccess access;
24+
25+
SsaUseNode() { this = TSsaUseNode(access) }
26+
27+
cached
28+
override string toString() { result = "[ssa-use] " + access.toString() }
29+
30+
cached
31+
override StmtContainer getContainer() { result = access.getContainer() }
32+
33+
cached
34+
override Location getLocation() { result = access.getLocation() }
35+
}
36+
37+
class SsaPhiReadNode extends DataFlow::Node, TSsaPhiReadNode {
38+
private Ssa2::PhiReadNode phi;
39+
40+
SsaPhiReadNode() { this = TSsaPhiReadNode(phi) }
41+
42+
cached
43+
override string toString() { result = "[ssa-phi-read] " + phi.getSourceVariable().getName() }
44+
45+
cached
46+
override StmtContainer getContainer() { result = phi.getSourceVariable().getDeclaringContainer() }
47+
48+
cached
49+
override Location getLocation() { result = phi.getLocation() }
50+
}
51+
52+
class SsaInputNode extends DataFlow::Node, TSsaInputNode {
53+
private Ssa2::SsaInputNode input;
54+
55+
SsaInputNode() { this = TSsaInputNode(input) }
56+
57+
cached
58+
override string toString() {
59+
result = "[ssa-input] " + input.getDefinitionExt().getSourceVariable().getName()
60+
}
61+
62+
cached
63+
override StmtContainer getContainer() {
64+
result = input.getDefinitionExt().getSourceVariable().getDeclaringContainer()
65+
}
66+
67+
cached
68+
override Location getLocation() { result = input.getLocation() }
69+
}
70+
2171
class FlowSummaryNode extends DataFlow::Node, TFlowSummaryNode {
2272
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
2373

@@ -535,6 +585,12 @@ predicate nodeIsHidden(Node node) {
535585
node instanceof DynamicParameterArrayNode
536586
or
537587
node instanceof RestParameterStoreNode
588+
or
589+
node instanceof SsaUseNode
590+
or
591+
node instanceof SsaPhiReadNode
592+
or
593+
node instanceof SsaInputNode
538594
}
539595

540596
predicate neverSkipInPathGraph(Node node) {
@@ -999,20 +1055,48 @@ private predicate valuePreservingStep(Node node1, Node node2) {
9991055
or
10001056
FlowSummaryPrivate::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
10011057
node2.(FlowSummaryNode).getSummaryNode(), true, _) // TODO: preserve 'model'
1002-
or
1003-
// Step from post-update nodes to local sources of the pre-update node. This emulates how JS usually tracks side effects.
1004-
exists(PostUpdateNode postUpdate |
1005-
node1 = postUpdate and
1006-
node2 = postUpdate.getPreUpdateNode().getALocalSource() and
1007-
node1 != node2 and // exclude trivial edges
1008-
sameContainer(node1, node2)
1009-
)
10101058
}
10111059

10121060
predicate knownSourceModel(Node sink, string model) { none() }
10131061

10141062
predicate knownSinkModel(Node sink, string model) { none() }
10151063

1064+
private predicate samePhi(SsaPhiNode legacyPhi, Ssa2::PhiNode newPhi) {
1065+
exists(BasicBlock bb, PurelyLocalVariable v |
1066+
newPhi.definesAt(v, bb, _) and
1067+
legacyPhi.definesAt(bb, _, v)
1068+
)
1069+
}
1070+
1071+
private Node getNodeFromSsa2(Ssa2::Node node) {
1072+
result = TSsaUseNode(node.(Ssa2::ExprNode).getExpr())
1073+
or
1074+
result = TExprPostUpdateNode(node.(Ssa2::ExprPostUpdateNode).getExpr())
1075+
or
1076+
result = TSsaPhiReadNode(node.(Ssa2::SsaDefinitionExtNode).getDefinitionExt())
1077+
or
1078+
result = TSsaInputNode(node.(Ssa2::SsaInputNode))
1079+
or
1080+
exists(SsaPhiNode legacyPhi, Ssa2::PhiNode ssaPhi |
1081+
node.(Ssa2::SsaDefinitionExtNode).getDefinitionExt() = ssaPhi and
1082+
samePhi(legacyPhi, ssaPhi) and
1083+
result = TSsaDefNode(legacyPhi)
1084+
)
1085+
}
1086+
1087+
private predicate useUseFlow(Node node1, Node node2) {
1088+
exists(Ssa2::DefinitionExt def, Ssa2::Node ssa1, Ssa2::Node ssa2, boolean isUseStep |
1089+
Ssa2::localFlowStep(def, ssa1, ssa2, isUseStep) and
1090+
node1 = getNodeFromSsa2(ssa1) and
1091+
node2 = getNodeFromSsa2(ssa2)
1092+
)
1093+
or
1094+
exists(VarUse use |
1095+
node1 = TSsaUseNode(use) and
1096+
node2 = TValueNode(use)
1097+
)
1098+
}
1099+
10161100
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
10171101
simpleLocalFlowStep(node1, node2) and model = ""
10181102
}
@@ -1022,6 +1106,8 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
10221106
nodeGetEnclosingCallable(pragma[only_bind_out](node1)) =
10231107
nodeGetEnclosingCallable(pragma[only_bind_out](node2))
10241108
or
1109+
useUseFlow(node1, node2)
1110+
or
10251111
exists(FlowSummaryImpl::Private::SummaryNode input, FlowSummaryImpl::Private::SummaryNode output |
10261112
FlowSummaryPrivate::Steps::summaryStoreStep(input, MkAwaited(), output) and
10271113
node1 = TFlowSummaryNode(input) and

javascript/ql/test/library-tests/TripleDot/useuse.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import 'dummy';
33
function t1() {
44
const obj = {};
55

6-
sink(obj.field); // $ SPURIOUS: hasValueFlow=t1.1 hasValueFlow=t1.2
6+
sink(obj.field);
77

88
obj.field = source('t1.1');
9-
sink(obj.field); // $ hasValueFlow=t1.1 SPURIOUS: hasValueFlow=t1.2
9+
sink(obj.field); // $ hasValueFlow=t1.1
1010

1111
obj.field = "safe";
12-
sink(obj.field); // $ SPURIOUS: hasValueFlow=t1.1 hasValueFlow=t1.2
12+
sink(obj.field); // $ SPURIOUS: hasValueFlow=t1.1
1313

1414
obj.field = source('t1.2');
1515
sink(obj.field); // $ hasValueFlow=t1.2 SPURIOUS: hasValueFlow=t1.1

0 commit comments

Comments
 (0)