@@ -112,6 +112,33 @@ class FlowSummaryIntermediateAwaitStoreNode extends DataFlow::Node,
112112 }
113113}
114114
115+ predicate mentionsExceptionalReturn ( FlowSummaryImpl:: Public:: SummarizedCallable callable ) {
116+ exists ( FlowSummaryImpl:: Private:: SummaryNode node | node .getSummarizedCallable ( ) = callable |
117+ FlowSummaryImpl:: Private:: summaryReturnNode ( node , MkExceptionalReturnKind ( ) )
118+ or
119+ FlowSummaryImpl:: Private:: summaryOutNode ( _, node , MkExceptionalReturnKind ( ) )
120+ )
121+ }
122+
123+ /**
124+ * Exceptional return node in a summarized callable whose summary does not mention `ReturnValue[exception]`.
125+ *
126+ * By default, every call inside such a callable will forward their exceptional return to the caller's
127+ * exceptional return, i.e. exceptions are not caught.
128+ */
129+ class FlowSummaryDefaultExceptionalReturn extends DataFlow:: Node ,
130+ TFlowSummaryDefaultExceptionalReturn
131+ {
132+ private FlowSummaryImpl:: Public:: SummarizedCallable callable ;
133+
134+ FlowSummaryDefaultExceptionalReturn ( ) { this = TFlowSummaryDefaultExceptionalReturn ( callable ) }
135+
136+ FlowSummaryImpl:: Public:: SummarizedCallable getSummarizedCallable ( ) { result = callable }
137+
138+ cached
139+ override string toString ( ) { result = "[default exceptional return] " + callable }
140+ }
141+
115142class CaptureNode extends DataFlow:: Node , TSynthCaptureNode {
116143 /** Gets the underlying node from the variable-capture library. */
117144 VariableCaptureOutput:: SynthesizedCaptureNode getNode ( ) {
@@ -296,6 +323,9 @@ private predicate returnNodeImpl(DataFlow::Node node, ReturnKind kind) {
296323 )
297324 or
298325 FlowSummaryImpl:: Private:: summaryReturnNode ( node .( FlowSummaryNode ) .getSummaryNode ( ) , kind )
326+ or
327+ node instanceof FlowSummaryDefaultExceptionalReturn and
328+ kind = MkExceptionalReturnKind ( )
299329}
300330
301331private DataFlow:: Node getAnOutNodeImpl ( DataFlowCall call , ReturnKind kind ) {
@@ -311,6 +341,10 @@ private DataFlow::Node getAnOutNodeImpl(DataFlowCall call, ReturnKind kind) {
311341 or
312342 FlowSummaryImpl:: Private:: summaryOutNode ( call .( SummaryCall ) .getReceiver ( ) ,
313343 result .( FlowSummaryNode ) .getSummaryNode ( ) , kind )
344+ or
345+ kind = MkExceptionalReturnKind ( ) and
346+ result .( FlowSummaryDefaultExceptionalReturn ) .getSummarizedCallable ( ) =
347+ call .( SummaryCall ) .getSummarizedCallable ( )
314348}
315349
316350class ReturnNode extends DataFlow:: Node {
@@ -404,6 +438,19 @@ abstract class LibraryCallable extends string {
404438 DataFlow:: InvokeNode getACallSimple ( ) { none ( ) }
405439}
406440
441+ /** Internal subclass of `LibraryCallable`, whose member predicates should not be visible on `SummarizedCallable`. */
442+ abstract class LibraryCallableInternal extends LibraryCallable {
443+ bindingset [ this ]
444+ LibraryCallableInternal ( ) { any ( ) }
445+
446+ /**
447+ * Gets a call to this library callable.
448+ *
449+ * Same as `getACall()` but is evaluated later and may depend negatively on `getACall()`.
450+ */
451+ DataFlow:: InvokeNode getACallStage2 ( ) { none ( ) }
452+ }
453+
407454private predicate isParameterNodeImpl ( Node p , DataFlowCallable c , ParameterPosition pos ) {
408455 exists ( Parameter parameter |
409456 parameter = c .asSourceCallable ( ) .( Function ) .getParameter ( pos .asPositional ( ) ) and
@@ -505,6 +552,8 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
505552 or
506553 result .asLibraryCallable ( ) = node .( FlowSummaryIntermediateAwaitStoreNode ) .getSummarizedCallable ( )
507554 or
555+ result .asLibraryCallable ( ) = node .( FlowSummaryDefaultExceptionalReturn ) .getSummarizedCallable ( )
556+ or
508557 node = TGenericSynthesizedNode ( _, _, result )
509558}
510559
@@ -865,6 +914,8 @@ class SummaryCall extends DataFlowCall, MkSummaryCall {
865914
866915 /** Gets the receiver node. */
867916 FlowSummaryImpl:: Private:: SummaryNode getReceiver ( ) { result = receiver }
917+
918+ FlowSummaryImpl:: Public:: SummarizedCallable getSummarizedCallable ( ) { result = enclosingCallable }
868919}
869920
870921/**
@@ -976,7 +1027,11 @@ DataFlowCallable viableCallable(DataFlowCall node) {
9761027 or
9771028 exists ( LibraryCallable callable |
9781029 result = MkLibraryCallable ( callable ) and
979- node .asOrdinaryCall ( ) = [ callable .getACall ( ) , callable .getACallSimple ( ) ]
1030+ node .asOrdinaryCall ( ) =
1031+ [
1032+ callable .getACall ( ) , callable .getACallSimple ( ) ,
1033+ callable .( LibraryCallableInternal ) .getACallStage2 ( )
1034+ ]
9801035 )
9811036 or
9821037 result .asSourceCallableNotExterns ( ) = node .asImpliedLambdaCall ( )
@@ -1217,14 +1272,29 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
12171272
12181273predicate localMustFlowStep ( Node node1 , Node node2 ) { node1 = node2 .getImmediatePredecessor ( ) }
12191274
1275+ /**
1276+ * Holds if `node1 -> node2` should be removed as a jump step.
1277+ *
1278+ * Currently this is done as a workaround for the local steps generated from IIFEs.
1279+ */
1280+ private predicate excludedJumpStep ( Node node1 , Node node2 ) {
1281+ exists ( ImmediatelyInvokedFunctionExpr iife |
1282+ iife .argumentPassing ( node2 .asExpr ( ) , node1 .asExpr ( ) )
1283+ or
1284+ node1 = iife .getAReturnedExpr ( ) .flow ( ) and
1285+ node2 = iife .getInvocation ( ) .flow ( )
1286+ )
1287+ }
1288+
12201289/**
12211290 * Holds if data can flow from `node1` to `node2` through a non-local step
12221291 * that does not follow a call edge. For example, a step through a global
12231292 * variable.
12241293 */
12251294predicate jumpStep ( Node node1 , Node node2 ) {
12261295 valuePreservingStep ( node1 , node2 ) and
1227- node1 .getContainer ( ) != node2 .getContainer ( )
1296+ node1 .getContainer ( ) != node2 .getContainer ( ) and
1297+ not excludedJumpStep ( node1 , node2 )
12281298 or
12291299 FlowSummaryPrivate:: Steps:: summaryJumpStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) ,
12301300 node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
0 commit comments