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

Skip to content

Commit 530fa2c

Browse files
author
Max Schaefer
committed
JavaScript: Collapse edges instead of hiding nodes.
Instead of skipping over initial and final nodes, we now introduce edges from source and to sink nodes that circumvent these nodes entirely.
1 parent dc1d1c2 commit 530fa2c

1 file changed

Lines changed: 78 additions & 25 deletions

File tree

javascript/ql/src/semmle/javascript/dataflow/Configuration.qll

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,27 +1042,42 @@ class PathNode extends TPathNode {
10421042
}
10431043
}
10441044

1045-
private PathNode getASuccessor(PathNode pnd) {
1045+
/** Gets the mid node corresponding to `src`. */
1046+
private MidPathNode initialMidNode(SourcePathNode src) {
10461047
exists(DataFlow::Node nd, Configuration cfg, PathSummary summary |
1047-
// source node to mid node
1048-
pnd = MkSourceNode(nd, cfg) and
1049-
isSourceNode(nd, cfg, summary) and
1050-
result = MkMidNode(nd, cfg, summary)
1051-
or
1052-
// mid node to mid node
1053-
pnd = MkMidNode(nd, cfg, summary) and
1054-
exists(DataFlow::Node succ, PathSummary newSummary |
1055-
flowStep(nd, id(cfg), succ, newSummary) and
1056-
result = MkMidNode(succ, id(cfg), summary.append(newSummary))
1057-
)
1058-
or
1059-
// mid node to sink node
1060-
pnd = MkMidNode(nd, cfg, summary) and
1061-
isSinkNode(nd, cfg, summary) and
1062-
result = MkSinkNode(nd, cfg)
1048+
result.wraps(nd, cfg, summary) and
1049+
src = MkSourceNode(nd, cfg) and
1050+
isSourceNode(nd, cfg, summary)
10631051
)
10641052
}
10651053

1054+
/** Gets the mid node corresponding to `snk`. */
1055+
private MidPathNode finalMidNode(SinkPathNode snk) {
1056+
exists(DataFlow::Node nd, Configuration cfg, PathSummary summary |
1057+
result.wraps(nd, cfg, summary) and
1058+
snk = MkSinkNode(nd, cfg) and
1059+
isSinkNode(nd, cfg, summary)
1060+
)
1061+
}
1062+
1063+
/**
1064+
* Gets a node to which data from `nd` may flow in one step.
1065+
*/
1066+
private PathNode getASuccessor(PathNode nd) {
1067+
// source node to mid node
1068+
result = initialMidNode(nd)
1069+
or
1070+
// mid node to mid node
1071+
exists(Configuration cfg, DataFlow::Node predNd, PathSummary summary, DataFlow::Node succNd, PathSummary newSummary |
1072+
nd = MkMidNode(predNd, cfg, summary) and
1073+
flowStep(predNd, id(cfg), succNd, newSummary) and
1074+
result = MkMidNode(succNd, id(cfg), summary.append(newSummary))
1075+
)
1076+
or
1077+
// mid node to sink node
1078+
nd = finalMidNode(result)
1079+
}
1080+
10661081
private PathNode getASuccessorIfHidden(PathNode nd) {
10671082
nd.(MidPathNode).isHidden() and
10681083
result = getASuccessor(nd)
@@ -1083,6 +1098,11 @@ class MidPathNode extends PathNode, MkMidNode {
10831098
/** Gets the summary of the path underlying this path node. */
10841099
PathSummary getPathSummary() { result = summary }
10851100

1101+
/** Holds if this path node wraps data-flow node `nd`, configuration `c` and summary `s`. */
1102+
predicate wraps(DataFlow::Node n, DataFlow::Configuration c, PathSummary s) {
1103+
nd = n and cfg = c and summary = s
1104+
}
1105+
10861106
/**
10871107
* Holds if this node is hidden from paths in path explanation queries, except
10881108
* in cases where it is the source or sink.
@@ -1095,12 +1115,6 @@ class MidPathNode extends PathNode, MkMidNode {
10951115
// Skip to the top of big left-leaning string concatenation trees.
10961116
nd = any(AddExpr add).flow() and
10971117
nd = any(AddExpr add).getAnOperand().flow()
1098-
or
1099-
// Skip mid node immediately following a source node
1100-
exists(MkSourceNode(nd, cfg))
1101-
or
1102-
// Skip mid node immediately preceding a sink node
1103-
exists(MkSinkNode(nd, cfg))
11041118
}
11051119
}
11061120

@@ -1127,9 +1141,48 @@ module PathGraph {
11271141
not nd.(MidPathNode).isHidden()
11281142
}
11291143

1144+
/**
1145+
* Gets a node to which data from `nd` may flow in one step, skipping over hidden nodes.
1146+
*/
1147+
private PathNode succ0(PathNode nd) {
1148+
result = getASuccessorIfHidden*(nd.getASuccessor()) and
1149+
// skip hidden nodes
1150+
nodes(nd) and nodes(result)
1151+
}
1152+
1153+
/**
1154+
* Gets a node to which data from `nd` may flow in one step, where outgoing edges from intermediate
1155+
* nodes are merged with any incoming edge from a corresponding source node.
1156+
*
1157+
* For example, assume that `src` is a source node for `nd1`, which has `nd2` as its direct
1158+
* successor. Then `succ0` will yield two edges `src` → `nd1` and `nd1` → `nd2`,
1159+
* to which `succ1` will add the edge `src` → `nd2`.
1160+
*/
1161+
private PathNode succ1(PathNode nd) {
1162+
result = succ0(nd)
1163+
or
1164+
result = succ0(initialMidNode(nd))
1165+
}
1166+
1167+
/**
1168+
* Gets a node to which data from `nd` may flow in one step, where incoming edges into intermediate
1169+
* nodes are merged with any outgoing edge to a corresponding sink node.
1170+
*
1171+
* For example, assume that `snk` is a source node for `nd2`, which has `nd1` as its direct
1172+
* predecessor. Then `succ1` will yield two edges `nd1` → `nd2` and `nd2` → `snk`,
1173+
* while `succ2` will yield just one edge `nd1` → `snk`.
1174+
*/
1175+
private PathNode succ2(PathNode nd) {
1176+
result = succ1(nd)
1177+
or
1178+
succ1(nd) = finalMidNode(result)
1179+
}
1180+
11301181
/** Holds if `pred` → `succ` is an edge in the graph of data flow path explanations. */
11311182
query predicate edges(PathNode pred, PathNode succ) {
1132-
succ = getASuccessorIfHidden*(pred.getASuccessor()) and
1133-
nodes(pred) and nodes(succ)
1183+
succ = succ2(pred) and
1184+
// skip over uninteresting edges
1185+
not succ = initialMidNode(pred) and
1186+
not pred = finalMidNode(succ)
11341187
}
11351188
}

0 commit comments

Comments
 (0)