@@ -78,21 +78,20 @@ class InvokeNode extends DataFlow::SourceNode {
7878 }
7979
8080 /** Gets an abstract value representing possible callees of this call site. */
81- cached
82- AbstractValue getACalleeValue ( ) { result = impl .getCalleeNode ( ) .analyze ( ) .getAValue ( ) }
83-
84- /** Gets a potential callee based on dataflow analysis results. */
85- private Function getACalleeFromDataflow ( ) {
86- result = getACalleeValue ( ) .( AbstractCallable ) .getFunction ( )
87- }
81+ AbstractValue getACalleeValue ( ) { result = InvokeNode:: getACalleeValue ( this ) }
8882
8983 /** Gets a potential callee of this call site. */
90- Function getACallee ( ) {
91- result = getACalleeFromDataflow ( )
92- or
93- not exists ( getACalleeFromDataflow ( ) ) and
94- result = impl .( DataFlow:: Impl:: ExplicitInvokeNode ) .asExpr ( ) .( InvokeExpr ) .getResolvedCallee ( )
95- }
84+ Function getACallee ( ) { result = InvokeNode:: getACallee ( this ) }
85+
86+ /**
87+ * Gets a callee of this call site where `imprecision` is a heuristic measure of how
88+ * likely it is that `callee` is only suggested as a potential callee due to
89+ * imprecise analysis of global variables and is not, in fact, a viable callee at all.
90+ *
91+ * Callees with imprecision zero, in particular, have either been derived without
92+ * considering global variables, or are calls to a global variable within the same file.
93+ */
94+ Function getACallee ( int imprecision ) { result = InvokeNode:: getACallee ( this , imprecision ) }
9695
9796 /**
9897 * Holds if the approximation of possible callees for this call site is
@@ -133,6 +132,60 @@ class InvokeNode extends DataFlow::SourceNode {
133132 predicate isUncertain ( ) { isImprecise ( ) or isIncomplete ( ) }
134133}
135134
135+ /** Auxiliary module used to cache a few related predicates together. */
136+ cached
137+ private module InvokeNode {
138+ /** Gets an abstract value representing possible callees of `invk`. */
139+ cached
140+ AbstractValue getACalleeValue ( InvokeNode invk ) {
141+ result = invk .getCalleeNode ( ) .analyze ( ) .getAValue ( )
142+ }
143+
144+ /** Gets a potential callee of `invk` based on dataflow analysis results. */
145+ private Function getACalleeFromDataflow ( InvokeNode invk ) {
146+ result = getACalleeValue ( invk ) .( AbstractCallable ) .getFunction ( )
147+ }
148+
149+ /** Gets a potential callee of `invk`. */
150+ cached
151+ Function getACallee ( InvokeNode invk ) {
152+ result = getACalleeFromDataflow ( invk )
153+ or
154+ not exists ( getACalleeFromDataflow ( invk ) ) and
155+ result = invk .( DataFlow:: Impl:: ExplicitInvokeNode ) .asExpr ( ) .( InvokeExpr ) .getResolvedCallee ( )
156+ }
157+
158+ /**
159+ * Gets a callee of `invk` where `imprecision` is a heuristic measure of how
160+ * likely it is that `callee` is only suggested as a potential callee due to
161+ * imprecise analysis of global variables and is not, in fact, a viable callee at all.
162+ *
163+ * Callees with imprecision zero, in particular, have either been derived without
164+ * considering global variables, or are calls to a global variable within the same file.
165+ */
166+ cached
167+ Function getACallee ( InvokeNode invk , int imprecision ) {
168+ result = getACallee ( invk ) and
169+ (
170+ // if global flow was used to derive the callee, we may be imprecise
171+ if invk .isIndefinite ( "global" )
172+ then
173+ // callees within the same file are probably genuine
174+ result .getFile ( ) = invk .getFile ( ) and imprecision = 0
175+ or
176+ // calls to global functions declared in an externs file are fairly
177+ // safe as well
178+ result .inExternsFile ( ) and imprecision = 1
179+ or
180+ // otherwise we make worst-case assumptions
181+ imprecision = 2
182+ else
183+ // no global flow, so no imprecision
184+ imprecision = 0
185+ )
186+ }
187+ }
188+
136189/** A data flow node corresponding to a function call without `new`. */
137190class CallNode extends InvokeNode {
138191 override DataFlow:: Impl:: CallNodeDef impl ;
0 commit comments