@@ -6,6 +6,7 @@ private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
66private import semmle.javascript.dataflow.internal.Contents:: Private
77private import semmle.javascript.dataflow.internal.VariableCapture
88private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
9+ private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
910private import semmle.javascript.internal.flow_summaries.AllFlowSummaries
1011private import sharedlib.FlowSummaryImpl as FlowSummaryImpl
1112private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
@@ -18,6 +19,55 @@ private class Node = DataFlow::Node;
1819
1920class 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+
2171class 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
540596predicate 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
10121060predicate knownSourceModel ( Node sink , string model ) { none ( ) }
10131061
10141062predicate 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+
10161100predicate 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
0 commit comments