@@ -224,7 +224,7 @@ signature predicate interestedInEquality(Type a, Type b);
224224 * Note that `equalTypes(a, b)` only holds if `interestedIn(a, b)` holds. A type is always
225225 * considered to be equal to itself, and this module does not support configurations that declare
226226 * otherwise.
227- *
227+ *
228228 * Further, `interestedInEquality(a, a)` is treated differently from `interestedInEquality(a, b)`,
229229 * assuming that `a` and `b` are not identical. This is so that we can construct a set of types
230230 * that are not identical, but still may be equivalent by the specified configuration. We also must
@@ -233,45 +233,75 @@ signature predicate interestedInEquality(Type a, Type b);
233233 * only a few are not.
234234 */
235235module TypeEquivalence< TypeEquivalenceSig Config, interestedInEquality / 2 interestedIn> {
236+
236237 /**
237- * Check whether two types are equivalent, as defined by the `TypeEquivalenceSig` module.
238- *
239- * This only holds if the specified predicate `interestedIn` holds for the types, and always
240- * holds if `t1` and `t2` are identical.
238+ * Performance related predicate to force top down rather than bottom up evaluation of type
239+ * equivalence.
241240 */
242- predicate equalTypes ( Type t1 , Type t2 ) {
243- interestedInUnordered ( t1 , t2 ) and
244- (
245- // If the types are identical, they are trivially equal.
246- t1 = t2
241+ predicate compares ( Type t1 , Type t2 ) {
242+ interestedIn ( t1 , t2 )
243+ or
244+ exists ( DerivedType t1Derived , DerivedType t2Derived |
245+ not t1Derived instanceof SpecifiedType and
246+ not t2Derived instanceof SpecifiedType and
247+ compares ( pragma [ only_bind_into ] ( t1Derived ) , pragma [ only_bind_into ] ( t2Derived ) ) and
248+ t1 = t1Derived .getBaseType ( ) and
249+ t2 = t2Derived .getBaseType ( )
250+ )
251+ or
252+ exists ( SpecifiedType t1Spec , SpecifiedType t2Spec |
253+ compares ( pragma [ only_bind_into ] ( t1Spec ) , pragma [ only_bind_into ] ( t2Spec ) ) and
254+ (
255+ t1 = unspecify ( t1Spec ) and
256+ t2 = unspecify ( t2Spec )
257+ )
258+ )
259+ or
260+ exists ( FunctionType t1Func , FunctionType t2Func |
261+ compares ( pragma [ only_bind_into ] ( t1Func ) , pragma [ only_bind_into ] ( t2Func ) ) and
262+ (
263+ t1 = t1Func .getReturnType ( ) and
264+ t2 = t2Func .getReturnType ( )
265+ or
266+ exists ( int i |
267+ t1 = t1Func .getParameterType ( pragma [ only_bind_out ] ( i ) ) and
268+ t2 = t2Func .getParameterType ( i )
269+ )
270+ )
271+ )
272+ or
273+ Config:: resolveTypedefs ( ) and
274+ exists ( TypedefType tdtype |
275+ tdtype .getBaseType ( ) = t1 and
276+ compares ( pragma [ only_bind_into ] ( tdtype ) , t2 )
247277 or
248- not t1 = t2 and
249- equalTypesImpl ( t1 , t2 )
278+ tdtype . getBaseType ( ) = t2 and
279+ compares ( t1 , pragma [ only_bind_into ] ( tdtype ) )
250280 )
251281 }
252282
253283 /**
254- * This implementation handles only the slow and complex cases of type equivalence, where the
255- * types are not identical.
284+ * Check whether two types are equivalent, as defined by the `TypeEquivalenceSig` module.
256285 *
257- * Assuming that types a, b must be compared where `a` and `b` are not identical, we wish to
258- * search only the smallest set of possible relevant types. See `RelevantType` for more .
286+ * This only holds if the specified predicate `interestedIn` holds for the types, and always
287+ * holds if `t1` and `t2` are identical .
259288 */
260- private predicate equalTypesImpl ( RelevantType t1 , RelevantType t2 ) {
289+ private predicate equalTypes ( Type t1 , Type t2 ) {
290+ compares ( pragma [ only_bind_into ] ( t1 ) , pragma [ only_bind_into ] ( t2 ) ) and
261291 if Config:: overrideTypeComparison ( t1 , t2 , _)
262292 then Config:: overrideTypeComparison ( t1 , t2 , true )
263293 else
264294 if t1 instanceof TypedefType and Config:: resolveTypedefs ( )
265- then equalTypesImpl ( t1 .( TypedefType ) .getBaseType ( ) , t2 )
295+ then equalTypes ( t1 .( TypedefType ) .getBaseType ( ) , t2 )
266296 else
267297 if t2 instanceof TypedefType and Config:: resolveTypedefs ( )
268- then equalTypesImpl ( t1 , t2 .( TypedefType ) .getBaseType ( ) )
298+ then equalTypes ( t1 , t2 .( TypedefType ) .getBaseType ( ) )
269299 else (
270300 not t1 instanceof DerivedType and
271301 not t2 instanceof DerivedType and
272302 not t1 instanceof TypedefType and
273303 not t2 instanceof TypedefType and
274- LeafEquiv :: getEquivalenceClass ( t1 ) = LeafEquiv :: getEquivalenceClass ( t2 )
304+ equalLeafRelation ( t1 , t2 )
275305 or
276306 equalDerivedTypes ( t1 , t2 )
277307 or
@@ -284,56 +314,14 @@ module TypeEquivalence<TypeEquivalenceSig Config, interestedInEquality/2 interes
284314 /** Whether two types will be compared, regardless of order (a, b) or (b, a). */
285315 private predicate interestedInUnordered ( Type t1 , Type t2 ) {
286316 interestedIn ( t1 , t2 ) or
287- interestedIn ( t2 , t1 ) }
288-
289- final private class FinalType = Type ;
290-
291- /**
292- * A type that is compared to another type that is not identical. This is the set of types that
293- * form the roots of our more expensive type equivalence analysis.
294- */
295- private class InterestingType extends FinalType {
296- InterestingType ( ) {
297- exists ( Type inexactCompare |
298- interestedInUnordered ( this , _) and
299- not inexactCompare = this
300- )
301- }
302- }
303-
304- /**
305- * A type that is reachable from an `InterestingType` (a type that is compared to a non-identical
306- * type).
307- *
308- * Since type equivalence is recursive, CodeQL will consider the equality of these types in a
309- * bottom-up evaluation, with leaf nodes first. Therefore, this set must be as small as possible
310- * in order to be efficient.
311- */
312- private class RelevantType extends FinalType {
313- RelevantType ( ) { exists ( InterestingType t | typeGraph * ( t , this ) ) }
317+ interestedIn ( t2 , t1 )
314318 }
315319
316- private class RelevantDerivedType extends RelevantType instanceof DerivedType {
317- RelevantType getBaseType ( ) { result = this .( DerivedType ) .getBaseType ( ) }
318- }
319-
320- private class RelevantFunctionType extends RelevantType instanceof FunctionType {
321- RelevantType getReturnType ( ) { result = this .( FunctionType ) .getReturnType ( ) }
322-
323- RelevantType getParameterType ( int i ) { result = this .( FunctionType ) .getParameterType ( i ) }
324- }
325-
326- private class RelevantTypedefType extends RelevantType instanceof TypedefType {
327- RelevantType getBaseType ( ) { result = this .( TypedefType ) .getBaseType ( ) }
328- }
329-
330- private module LeafEquiv = QlBuiltins:: EquivalenceRelation< RelevantType , equalLeafRelation / 2 > ;
331-
332- private predicate equalLeafRelation ( RelevantType t1 , RelevantType t2 ) {
333- Config:: equalLeafTypes ( t1 , t2 )
334- }
320+ bindingset [ t1, t2]
321+ private predicate equalLeafRelation ( Type t1 , Type t2 ) { Config:: equalLeafTypes ( t1 , t2 ) }
335322
336- private RelevantType unspecify ( SpecifiedType t ) {
323+ bindingset [ t]
324+ private Type unspecify ( SpecifiedType t ) {
337325 // This subtly and importantly handles the complicated cases of typedefs. Under most scenarios,
338326 // if we see a typedef in `equalTypes()` we can simply get the base type and continue. However,
339327 // there is an exception if we have a specified type that points to a typedef that points to
@@ -347,9 +335,9 @@ module TypeEquivalence<TypeEquivalenceSig Config, interestedInEquality/2 interes
347335 }
348336
349337 bindingset [ t1, t2]
350- private predicate equalDerivedTypes ( RelevantDerivedType t1 , RelevantDerivedType t2 ) {
338+ private predicate equalDerivedTypes ( DerivedType t1 , DerivedType t2 ) {
351339 exists ( Boolean baseTypesEqual |
352- ( baseTypesEqual = true implies equalTypesImpl ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
340+ ( baseTypesEqual = true implies equalTypes ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
353341 (
354342 Config:: equalPointerTypes ( t1 , t2 , baseTypesEqual )
355343 or
@@ -363,20 +351,20 @@ module TypeEquivalence<TypeEquivalenceSig Config, interestedInEquality/2 interes
363351 // Note that this case is different from the above, in that we don't merely get the base
364352 // type (as that could be a TypedefType that points to another SpecifiedType). We need to
365353 // unspecify the type to see if the base types are equal.
366- ( unspecifiedTypesEqual = true implies equalTypesImpl ( unspecify ( t1 ) , unspecify ( t2 ) ) ) and
354+ ( unspecifiedTypesEqual = true implies equalTypes ( unspecify ( t1 ) , unspecify ( t2 ) ) ) and
367355 Config:: equalSpecifiedTypes ( t1 , t2 , unspecifiedTypesEqual )
368356 )
369357 }
370358
371359 bindingset [ t1, t2]
372- private predicate equalFunctionTypes ( RelevantFunctionType t1 , RelevantFunctionType t2 ) {
360+ private predicate equalFunctionTypes ( FunctionType t1 , FunctionType t2 ) {
373361 exists ( Boolean returnTypeEqual , Boolean parameterTypesEqual |
374- ( returnTypeEqual = true implies equalTypesImpl ( t1 .getReturnType ( ) , t2 .getReturnType ( ) ) ) and
362+ ( returnTypeEqual = true implies equalTypes ( t1 .getReturnType ( ) , t2 .getReturnType ( ) ) ) and
375363 (
376364 parameterTypesEqual = true
377365 implies
378366 forall ( int i | exists ( [ t1 , t2 ] .getParameterType ( i ) ) |
379- equalTypesImpl ( t1 .getParameterType ( i ) , t2 .getParameterType ( i ) )
367+ equalTypes ( t1 .getParameterType ( i ) , t2 .getParameterType ( i ) )
380368 )
381369 ) and
382370 (
@@ -388,9 +376,9 @@ module TypeEquivalence<TypeEquivalenceSig Config, interestedInEquality/2 interes
388376 }
389377
390378 bindingset [ t1, t2]
391- private predicate equalTypedefTypes ( RelevantTypedefType t1 , RelevantTypedefType t2 ) {
379+ private predicate equalTypedefTypes ( TypedefType t1 , TypedefType t2 ) {
392380 exists ( Boolean baseTypesEqual |
393- ( baseTypesEqual = true implies equalTypesImpl ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
381+ ( baseTypesEqual = true implies equalTypes ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
394382 Config:: equalTypedefTypes ( t1 , t2 , baseTypesEqual )
395383 )
396384 }
0 commit comments