@@ -25,7 +25,7 @@ class VariableType extends Type {
2525}
2626
2727predicate parameterNamesUnmatched ( FunctionDeclarationEntry f1 , FunctionDeclarationEntry f2 ) {
28- f1 .getDeclaration ( ) = f2 .getDeclaration ( ) and
28+ pragma [ only_bind_into ] ( f1 ) .getDeclaration ( ) = pragma [ only_bind_into ] ( f2 ) .getDeclaration ( ) and
2929exists ( string p1Name , string p2Name , int i |
3030p1Name = f1 .getParameterDeclarationEntry ( i ) .getName ( ) and
3131p2Name = f2 .getParameterDeclarationEntry ( i ) .getName ( )
@@ -208,34 +208,64 @@ signature module TypeEquivalenceSig {
208208module DefaultEquivalenceimplements TypeEquivalenceSig { }
209209
210210/**
211- * A signatureclass used to restrict the set of types considered by `TypeEquivalence`, for
211+ * A signaturepredicate used to restrict the set of types considered by `TypeEquivalence`, for
212212 * performance reasons.
213213 */
214- signature class TypeSubset extends Type ;
214+ signature predicate interestedInEquality ( Type a , Type b ) ;
215215
216216/**
217217 * A module to check the equivalence of two types, as defined by the provided `TypeEquivalenceSig`.
218218 *
219- * For performance reasons, this module is designed to be used with a `TypeSubset` that restricts
220- * the set of considered types. All types reachable (in the type graph) from a type in the subset
221- * will be considered. (See `RelevantType`.)
219+ * For performance reasons, this module is designed to be used with a predicate
220+ * `interestedInEquality` that restricts the set of considered types.
222221 *
223222 * To use this module, define a `TypeEquivalenceSig` module and implement a subset of `Type` that
224223 * selects the relevant root types to be considered. Then use the predicate `equalTypes(a, b)`.
224+ * Note that `equalTypes(a, b)` only holds if `interestedIn(a, b)` holds. A type is always
225+ * considered to be equal to itself, and this module does not support configurations that declare
226+ * otherwise.
227+ *
228+ * Further, `interestedInEquality(a, a)` is treated differently from `interestedInEquality(a, b)`,
229+ * assuming that `a` and `b` are not identical. This is so that we can construct a set of types
230+ * that are not identical, but still may be equivalent by the specified configuration. We also must
231+ * consider all types that are reachable from these types, as the equivalence relation is
232+ * recursive. Therefore, this module is more performant when most comparisons are identical, and
233+ * only a few are not.
225234 */
226- module TypeEquivalence< TypeEquivalenceSig Config, TypeSubset T > {
235+ module TypeEquivalence< TypeEquivalenceSig Config, interestedInEquality / 2 interestedIn > {
227236/**
228237 * 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.
229241 */
230- predicate equalTypes ( RelevantType t1 , RelevantType t2 ) {
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
247+ or
248+ not t1 = t2 and
249+ equalTypesImpl ( t1 , t2 )
250+ )
251+ }
252+
253+ /**
254+ * This implementation handles only the slow and complex cases of type equivalence, where the
255+ * types are not identical.
256+ *
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.
259+ */
260+ private predicate equalTypesImpl ( RelevantType t1 , RelevantType t2 ) {
231261if Config:: overrideTypeComparison ( t1 , t2 , _)
232262then Config:: overrideTypeComparison ( t1 , t2 , true )
233263else
234264if t1 instanceof TypedefType and Config:: resolveTypedefs ( )
235- then equalTypes ( t1 .( TypedefType ) .getBaseType ( ) , t2 )
265+ then equalTypesImpl ( t1 .( TypedefType ) .getBaseType ( ) , t2 )
236266else
237267if t2 instanceof TypedefType and Config:: resolveTypedefs ( )
238- then equalTypes ( t1 , t2 .( TypedefType ) .getBaseType ( ) )
268+ then equalTypesImpl ( t1 , t2 .( TypedefType ) .getBaseType ( ) )
239269else (
240270not t1 instanceof DerivedType and
241271not t2 instanceof DerivedType and
@@ -251,13 +281,36 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
251281)
252282}
253283
284+ /** Whether two types will be compared, regardless of order (a, b) or (b, a). */
285+ private predicate interestedInUnordered ( Type t1 , Type t2 ) {
286+ interestedIn ( t1 , t2 ) or
287+ interestedIn ( t2 , t1 ) }
288+
289+ final private class FinalType = Type ;
290+
254291/**
255- * A type that is either part of the type subset, or that is reachable from a type in the subset.
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.
256294 */
257- private class RelevantType instanceof Type {
258- RelevantType ( ) { exists ( T t | typeGraph * ( t , this ) ) }
295+ private class InterestingType extends FinalType {
296+ InterestingType ( ) {
297+ exists ( Type inexactCompare |
298+ interestedInUnordered ( this , _) and
299+ not inexactCompare = this
300+ )
301+ }
302+ }
259303
260- string toString ( ) { result = this .( Type ) .toString ( ) }
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 ) ) }
261314}
262315
263316private class RelevantDerivedType extends RelevantType instanceof DerivedType {
@@ -296,7 +349,7 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
296349bindingset [ t1, t2]
297350private predicate equalDerivedTypes ( RelevantDerivedType t1 , RelevantDerivedType t2 ) {
298351exists ( Boolean baseTypesEqual |
299- ( baseTypesEqual = true implies equalTypes ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
352+ ( baseTypesEqual = true implies equalTypesImpl ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
300353(
301354 Config:: equalPointerTypes ( t1 , t2 , baseTypesEqual )
302355or
@@ -310,20 +363,20 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
310363// Note that this case is different from the above, in that we don't merely get the base
311364// type (as that could be a TypedefType that points to another SpecifiedType). We need to
312365// unspecify the type to see if the base types are equal.
313- ( unspecifiedTypesEqual = true implies equalTypes ( unspecify ( t1 ) , unspecify ( t2 ) ) ) and
366+ ( unspecifiedTypesEqual = true implies equalTypesImpl ( unspecify ( t1 ) , unspecify ( t2 ) ) ) and
314367 Config:: equalSpecifiedTypes ( t1 , t2 , unspecifiedTypesEqual )
315368)
316369}
317370
318371bindingset [ t1, t2]
319372private predicate equalFunctionTypes ( RelevantFunctionType t1 , RelevantFunctionType t2 ) {
320373exists ( Boolean returnTypeEqual , Boolean parameterTypesEqual |
321- ( returnTypeEqual = true implies equalTypes ( t1 .getReturnType ( ) , t2 .getReturnType ( ) ) ) and
374+ ( returnTypeEqual = true implies equalTypesImpl ( t1 .getReturnType ( ) , t2 .getReturnType ( ) ) ) and
322375(
323376parameterTypesEqual = true
324377implies
325378forall ( int i | exists ( [ t1 , t2 ] .getParameterType ( i ) ) |
326- equalTypes ( t1 .getParameterType ( i ) , t2 .getParameterType ( i ) )
379+ equalTypesImpl ( t1 .getParameterType ( i ) , t2 .getParameterType ( i ) )
327380)
328381) and
329382(
@@ -337,30 +390,52 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
337390bindingset [ t1, t2]
338391private predicate equalTypedefTypes ( RelevantTypedefType t1 , RelevantTypedefType t2 ) {
339392exists ( Boolean baseTypesEqual |
340- ( baseTypesEqual = true implies equalTypes ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
393+ ( baseTypesEqual = true implies equalTypesImpl ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
341394 Config:: equalTypedefTypes ( t1 , t2 , baseTypesEqual )
342395)
343396}
344397}
345398
346- module FunctionDeclarationTypeEquivalence< TypeEquivalenceSig Config> {
399+ signature predicate interestedInFunctionDeclarations (
400+ FunctionDeclarationEntry f1 , FunctionDeclarationEntry f2
401+ ) ;
402+
403+ module FunctionDeclarationTypeEquivalence<
404+ TypeEquivalenceSig Config, interestedInFunctionDeclarations / 2 interestedInFunctions>
405+ {
406+ private predicate interestedInReturnTypes ( Type a , Type b ) {
407+ exists ( FunctionDeclarationEntry aFun , FunctionDeclarationEntry bFun |
408+ interestedInFunctions ( aFun , bFun ) and
409+ a = aFun .getType ( ) and
410+ b = bFun .getType ( )
411+ )
412+ }
413+
414+ private predicate interestedInParameterTypes ( Type a , Type b ) {
415+ exists ( FunctionDeclarationEntry aFun , FunctionDeclarationEntry bFun , int i |
416+ interestedInFunctions ( pragma [ only_bind_into ] ( aFun ) , pragma [ only_bind_into ] ( bFun ) ) and
417+ a = aFun .getParameterDeclarationEntry ( i ) .getType ( ) and
418+ b = bFun .getParameterDeclarationEntry ( i ) .getType ( )
419+ )
420+ }
421+
347422predicate equalReturnTypes ( FunctionDeclarationEntry f1 , FunctionDeclarationEntry f2 ) {
348- TypeEquivalence< Config , FunctionSignatureType > :: equalTypes ( f1 .getType ( ) , f2 .getType ( ) )
423+ TypeEquivalence< Config , interestedInReturnTypes / 2 > :: equalTypes ( f1 .getType ( ) , f2 .getType ( ) )
349424}
350425
351426predicate equalParameterTypes ( FunctionDeclarationEntry f1 , FunctionDeclarationEntry f2 ) {
427+ interestedInFunctions ( f1 , f2 ) and
352428f1 .getDeclaration ( ) = f2 .getDeclaration ( ) and
353429forall ( int i | exists ( [ f1 , f2 ] .getParameterDeclarationEntry ( i ) ) |
354430equalParameterTypesAt ( f1 , f2 , pragma [ only_bind_into ] ( i ) )
355431)
356432}
357433
358434predicate equalParameterTypesAt ( FunctionDeclarationEntry f1 , FunctionDeclarationEntry f2 , int i ) {
359- pragma [ only_bind_out ] ( f1 .getDeclaration ( ) ) = pragma [ only_bind_out ] ( f2 .getDeclaration ( ) ) and
360- TypeEquivalence< Config , FunctionSignatureType > :: equalTypes (
361- f1 .getParameterDeclarationEntry ( i ) .getType ( ) ,
362- f2 .getParameterDeclarationEntry ( i ) .getType ( )
363- )
435+ interestedInFunctions ( f1 , f2 ) and
436+ f1 .getDeclaration ( ) = f2 .getDeclaration ( ) and
437+ TypeEquivalence< Config , interestedInParameterTypes / 2 > :: equalTypes ( f1 .getParameterDeclarationEntry ( pragma [ only_bind_into ] ( i ) )
438+ .getType ( ) , f2 .getParameterDeclarationEntry ( pragma [ only_bind_into ] ( i ) ) .getType ( ) )
364439}
365440}
366441