@@ -2,7 +2,37 @@ private import codeql.typeflow.TypeFlow
22private import codeql.util.Location
33private import codeql.util.Unit
44
5- module TypeFlow< LocationSig Location, TypeFlowInput< Location > I> {
5+ signature module UniversalFlowInput< LocationSig Location> {
6+ /**
7+ * A node for which certain data flow properties may be proved. For example,
8+ * expressions and method declarations.
9+ */
10+ class TypeFlowNode {
11+ /** Gets a textual representation of this node. */
12+ string toString ( ) ;
13+
14+ /** Gets the location of this node. */
15+ Location getLocation ( ) ;
16+ }
17+
18+ /**
19+ * Holds if data can flow from `n1` to `n2` in one step.
20+ *
21+ * For a given `n2`, this predicate must include all possible `n1` that can flow to `n2`.
22+ */
23+ predicate step ( TypeFlowNode n1 , TypeFlowNode n2 ) ;
24+
25+ /** Holds if `n` represents a `null` value. */
26+ predicate isNullValue ( TypeFlowNode n ) ;
27+
28+ /**
29+ * Holds if `n` should be excluded from the set of null values even if
30+ * the null analysis determines that `n` is always null.
31+ */
32+ default predicate isExcludedFromNullAnalysis ( TypeFlowNode n ) { none ( ) }
33+ }
34+
35+ module UfMake< LocationSig Location, UniversalFlowInput< Location > I> {
636 private import I
737
838 /**
@@ -31,11 +61,11 @@ module TypeFlow<LocationSig Location, TypeFlowInput<Location> I> {
3161 * Holds if data can flow from `n1` to `n2` in one step, `n1` is not necessarily
3262 * functionally determined by `n2`, and `n1` might take a non-null value.
3363 */
34- private predicate joinStepNotNull ( TypeFlowNode n1 , TypeFlowNode n2 ) {
64+ predicate joinStepNotNull ( TypeFlowNode n1 , TypeFlowNode n2 ) {
3565 joinStep ( n1 , n2 ) and not isNull ( n1 )
3666 }
3767
38- private predicate anyStep ( TypeFlowNode n1 , TypeFlowNode n2 ) {
68+ predicate anyStep ( TypeFlowNode n1 , TypeFlowNode n2 ) {
3969 joinStepNotNull ( n1 , n2 ) or uniqStep ( n1 , n2 )
4070 }
4171
@@ -168,34 +198,117 @@ module TypeFlow<LocationSig Location, TypeFlowInput<Location> I> {
168198
169199 private module RankedSccJoinStep = RankEdge< SccJoinStep > ;
170200
171- private module ExactTypePropagation implements TypePropagation {
172- class Typ = Type ;
201+ signature module NullaryPropertySig {
202+ predicate hasPropertyBase ( TypeFlowNode n ) ;
203+
204+ default predicate barrier ( TypeFlowNode n ) { none ( ) }
205+ }
206+
207+ module FlowNullary< NullaryPropertySig P> {
208+ private module Propagation implements TypePropagation {
209+ class Typ = Unit ;
173210
174- predicate candType = exactType / 2 ;
211+ predicate candType ( TypeFlowNode n , Unit u ) { hasProperty ( n ) and exists ( u ) }
175212
176- predicate supportsType = exactType / 2 ;
213+ predicate supportsType = candType / 2 ;
214+ }
215+
216+ predicate hasProperty ( TypeFlowNode n ) {
217+ P:: hasPropertyBase ( n )
218+ or
219+ not P:: barrier ( n ) and
220+ (
221+ exists ( TypeFlowNode mid | hasProperty ( mid ) and uniqStep ( mid , n ) )
222+ or
223+ // The following is an optimized version of
224+ // `forex(TypeFlowNode mid | joinStepNotNull(mid, n) | hasPropery(mid))`
225+ ForAll< TypeFlowNode , RankedJoinStep , Propagation > :: flowJoin ( n , _)
226+ or
227+ exists ( TypeFlowScc scc |
228+ sccRepr ( n , scc ) and
229+ // Optimized version of
230+ // `forex(TypeFlowNode mid | sccJoinStepNotNull(mid, scc) | hasPropery(mid))`
231+ ForAll< TypeFlowScc , RankedSccJoinStep , Propagation > :: flowJoin ( scc , _)
232+ )
233+ )
234+ }
235+ }
236+
237+ signature module PropertySig {
238+ class Prop ;
239+
240+ bindingset [ t1, t2]
241+ default predicate propImplies ( Prop t1 , Prop t2 ) { t1 = t2 }
242+
243+ predicate hasPropertyBase ( TypeFlowNode n , Prop t ) ;
244+
245+ default predicate barrier ( TypeFlowNode n ) { none ( ) }
246+ }
247+
248+ module Flow< PropertySig P> {
249+ private module Propagation implements TypePropagation {
250+ class Typ = P:: Prop ;
251+
252+ predicate candType = hasProperty / 2 ;
253+
254+ bindingset [ t]
255+ predicate supportsType ( TypeFlowNode n , Typ t ) {
256+ exists ( Typ t0 | hasProperty ( n , t0 ) and P:: propImplies ( t0 , t ) )
257+ }
258+ }
259+
260+ /**
261+ * Holds if the runtime type of `n` is exactly `t` and if this bound is a
262+ * non-trivial lower bound, that is, `t` has a subtype.
263+ */
264+ predicate hasProperty ( TypeFlowNode n , P:: Prop t ) {
265+ P:: hasPropertyBase ( n , t )
266+ or
267+ not P:: barrier ( n ) and
268+ (
269+ exists ( TypeFlowNode mid | hasProperty ( mid , t ) and uniqStep ( mid , n ) )
270+ or
271+ // The following is an optimized version of
272+ // `forex(TypeFlowNode mid | joinStepNotNull(mid, n) | hasPropery(mid, t))`
273+ ForAll< TypeFlowNode , RankedJoinStep , Propagation > :: flowJoin ( n , t )
274+ or
275+ exists ( TypeFlowScc scc |
276+ sccRepr ( n , scc ) and
277+ // Optimized version of
278+ // `forex(TypeFlowNode mid | sccJoinStepNotNull(mid, scc) | hasPropery(mid, t))`
279+ ForAll< TypeFlowScc , RankedSccJoinStep , Propagation > :: flowJoin ( scc , t )
280+ )
281+ )
282+ }
283+ }
284+ }
285+
286+ module TypeFlow< LocationSig Location, TypeFlowInput< Location > I> {
287+ private import I
288+
289+ private module UfInput implements UniversalFlowInput< Location > {
290+ class TypeFlowNode = I:: TypeFlowNode ;
291+
292+ predicate step = I:: step / 2 ;
293+
294+ predicate isNullValue = I:: isNullValue / 1 ;
295+
296+ predicate isExcludedFromNullAnalysis = I:: isExcludedFromNullAnalysis / 1 ;
297+ }
298+
299+ private module UnivFlow = UfMake< Location , UfInput > ;
300+
301+ private module ExactTypeProperty implements UnivFlow:: PropertySig {
302+ class Prop = Type ;
303+
304+ predicate hasPropertyBase = exactTypeBase / 2 ;
177305 }
178306
179307 /**
180308 * Holds if the runtime type of `n` is exactly `t` and if this bound is a
181309 * non-trivial lower bound, that is, `t` has a subtype.
182310 */
183- private predicate exactType ( TypeFlowNode n , Type t ) {
184- exactTypeBase ( n , t )
185- or
186- exists ( TypeFlowNode mid | exactType ( mid , t ) and uniqStep ( mid , n ) )
187- or
188- // The following is an optimized version of
189- // `forex(TypeFlowNode mid | joinStepNotNull(mid, n) | exactType(mid, t))`
190- ForAll< TypeFlowNode , RankedJoinStep , ExactTypePropagation > :: flowJoin ( n , t )
191- or
192- exists ( TypeFlowScc scc |
193- sccRepr ( n , scc ) and
194- // Optimized version of
195- // `forex(TypeFlowNode mid | sccJoinStepNotNull(mid, scc) | exactType(mid, t))`
196- ForAll< TypeFlowScc , RankedSccJoinStep , ExactTypePropagation > :: flowJoin ( scc , t )
197- )
198- }
311+ private predicate exactType = UnivFlow:: Flow< ExactTypeProperty > :: hasProperty / 2 ;
199312
200313 /**
201314 * Gets the source declaration of a direct supertype of this type, excluding itself.
@@ -226,34 +339,22 @@ module TypeFlow<LocationSig Location, TypeFlowInput<Location> I> {
226339 )
227340 }
228341
229- private module TypeFlowPropagation implements TypePropagation {
230- class Typ = Type ;
342+ private module TypeFlowProperty implements UnivFlow :: PropertySig {
343+ class Prop = Type ;
231344
232- predicate candType = typeFlow / 2 ;
345+ bindingset [ t1, t2]
346+ predicate propImplies ( Type t1 , Type t2 ) { getAnAncestor ( pragma [ only_bind_out ] ( t1 ) ) = t2 }
233347
234- bindingset [ t]
235- predicate supportsType ( TypeFlowNode mid , Type t ) {
236- exists ( Type midtyp | exactType ( mid , midtyp ) or typeFlow ( mid , midtyp ) |
237- getAnAncestor ( pragma [ only_bind_out ] ( midtyp ) ) = t
238- )
239- }
348+ predicate hasPropertyBase ( TypeFlowNode n , Prop t ) { typeFlowBase ( n , t ) or exactType ( n , t ) }
240349 }
241350
242351 /**
243352 * Holds if the runtime type of `n` is bounded by `t` and if this bound is
244353 * likely to be better than the static type of `n`.
245354 */
246355 private predicate typeFlow ( TypeFlowNode n , Type t ) {
247- typeFlowBase ( n , t )
248- or
249- exists ( TypeFlowNode mid | typeFlow ( mid , t ) and uniqStep ( mid , n ) )
250- or
251- ForAll< TypeFlowNode , RankedJoinStep , TypeFlowPropagation > :: flowJoin ( n , t )
252- or
253- exists ( TypeFlowScc scc |
254- sccRepr ( n , scc ) and
255- ForAll< TypeFlowScc , RankedSccJoinStep , TypeFlowPropagation > :: flowJoin ( scc , t )
256- )
356+ UnivFlow:: Flow< TypeFlowProperty > :: hasProperty ( n , t ) and
357+ not exactType ( n , t )
257358 }
258359
259360 pragma [ nomagic]
@@ -341,48 +442,28 @@ module TypeFlow<LocationSig Location, TypeFlowInput<Location> I> {
341442 */
342443 private predicate unionTypeFlowBaseCand ( TypeFlowNode n , Type t , boolean exact ) {
343444 exists ( TypeFlowNode next |
344- joinStepNotNull ( n , next ) and
445+ UnivFlow :: joinStepNotNull ( n , next ) and
345446 bestTypeFlowOrTypeFlowBase ( n , t , exact ) and
346447 not bestTypeFlowOrTypeFlowBase ( next , t , exact ) and
347448 not exactType ( next , _)
348449 )
349450 }
350451
351- private module HasUnionTypePropagation implements TypePropagation {
352- class Typ = Unit ;
353-
354- predicate candType ( TypeFlowNode mid , Unit unit ) {
355- exists ( unit ) and
356- ( unionTypeFlowBaseCand ( mid , _, _) or hasUnionTypeFlow ( mid ) )
452+ module UnionTypeFlowProperty implements UnivFlow:: NullaryPropertySig {
453+ predicate hasPropertyBase ( TypeFlowNode n ) {
454+ unionTypeFlowBaseCand ( n , _, _) or
455+ instanceofDisjunctionGuarded ( n , _)
357456 }
358457
359- predicate supportsType = candType / 2 ;
458+ predicate barrier ( TypeFlowNode n ) { exactType ( n , _ ) }
360459 }
361460
362461 /**
363462 * Holds if all incoming type flow can be traced back to a
364463 * `unionTypeFlowBaseCand`, such that we can compute a union type bound for `n`.
365464 * Disregards nodes for which we have an exact bound.
366465 */
367- private predicate hasUnionTypeFlow ( TypeFlowNode n ) {
368- not exactType ( n , _) and
369- (
370- // Optimized version of
371- // `forex(TypeFlowNode mid | joinStepNotNull(mid, n) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))`
372- ForAll< TypeFlowNode , RankedJoinStep , HasUnionTypePropagation > :: flowJoin ( n , _)
373- or
374- exists ( TypeFlowScc scc |
375- sccRepr ( n , scc ) and
376- // Optimized version of
377- // `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))`
378- ForAll< TypeFlowScc , RankedSccJoinStep , HasUnionTypePropagation > :: flowJoin ( scc , _)
379- )
380- or
381- exists ( TypeFlowNode mid | uniqStep ( mid , n ) and hasUnionTypeFlow ( mid ) )
382- or
383- instanceofDisjunctionGuarded ( n , _)
384- )
385- }
466+ private predicate hasUnionTypeFlow = UnivFlow:: FlowNullary< UnionTypeFlowProperty > :: hasProperty / 1 ;
386467
387468 pragma [ nomagic]
388469 private Type getTypeBound ( TypeFlowNode n ) {
@@ -395,9 +476,9 @@ module TypeFlow<LocationSig Location, TypeFlowInput<Location> I> {
395476 private predicate unionTypeFlow0 ( TypeFlowNode n , Type t , boolean exact ) {
396477 hasUnionTypeFlow ( n ) and
397478 (
398- exists ( TypeFlowNode mid | anyStep ( mid , n ) |
399- unionTypeFlowBaseCand ( mid , t , exact ) or unionTypeFlow ( mid , t , exact )
400- )
479+ exists ( TypeFlowNode mid | UnivFlow :: anyStep ( mid , n ) | unionTypeFlow ( mid , t , exact ) )
480+ or
481+ unionTypeFlowBaseCand ( n , t , exact )
401482 or
402483 instanceofDisjunctionGuarded ( n , t ) and exact = false
403484 )
@@ -482,6 +563,7 @@ module TypeFlow<LocationSig Location, TypeFlowInput<Location> I> {
482563 */
483564 predicate bestUnionType ( TypeFlowNode n , Type t , boolean exact ) {
484565 unionTypeFlow ( n , t , exact ) and
566+ not exactType ( n , _) and
485567 not irrelevantUnionType ( n ) and
486568 not irrelevantUnionTypePart ( n , t , exact )
487569 }
0 commit comments