@@ -25,7 +25,7 @@ class VariableType extends Type {
25
25
}
26
26
27
27
predicate 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
29
29
exists ( string p1Name , string p2Name , int i |
30
30
p1Name = f1 .getParameterDeclarationEntry ( i ) .getName ( ) and
31
31
p2Name = f2 .getParameterDeclarationEntry ( i ) .getName ( )
@@ -208,34 +208,64 @@ signature module TypeEquivalenceSig {
208
208
module DefaultEquivalence implements TypeEquivalenceSig { }
209
209
210
210
/**
211
- * A signature class used to restrict the set of types considered by `TypeEquivalence`, for
211
+ * A signature predicate used to restrict the set of types considered by `TypeEquivalence`, for
212
212
* performance reasons.
213
213
*/
214
- signature class TypeSubset extends Type ;
214
+ signature predicate interestedInEquality ( Type a , Type b ) ;
215
215
216
216
/**
217
217
* A module to check the equivalence of two types, as defined by the provided `TypeEquivalenceSig`.
218
218
*
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.
222
221
*
223
222
* To use this module, define a `TypeEquivalenceSig` module and implement a subset of `Type` that
224
223
* 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.
225
234
*/
226
- module TypeEquivalence< TypeEquivalenceSig Config, TypeSubset T > {
235
+ module TypeEquivalence< TypeEquivalenceSig Config, interestedInEquality / 2 interestedIn > {
227
236
/**
228
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.
229
241
*/
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 ) {
231
261
if Config:: overrideTypeComparison ( t1 , t2 , _)
232
262
then Config:: overrideTypeComparison ( t1 , t2 , true )
233
263
else
234
264
if t1 instanceof TypedefType and Config:: resolveTypedefs ( )
235
- then equalTypes ( t1 .( TypedefType ) .getBaseType ( ) , t2 )
265
+ then equalTypesImpl ( t1 .( TypedefType ) .getBaseType ( ) , t2 )
236
266
else
237
267
if t2 instanceof TypedefType and Config:: resolveTypedefs ( )
238
- then equalTypes ( t1 , t2 .( TypedefType ) .getBaseType ( ) )
268
+ then equalTypesImpl ( t1 , t2 .( TypedefType ) .getBaseType ( ) )
239
269
else (
240
270
not t1 instanceof DerivedType and
241
271
not t2 instanceof DerivedType and
@@ -251,13 +281,36 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
251
281
)
252
282
}
253
283
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
+
254
291
/**
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.
256
294
*/
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
+ }
259
303
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 ) ) }
261
314
}
262
315
263
316
private class RelevantDerivedType extends RelevantType instanceof DerivedType {
@@ -296,7 +349,7 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
296
349
bindingset [ t1, t2]
297
350
private predicate equalDerivedTypes ( RelevantDerivedType t1 , RelevantDerivedType t2 ) {
298
351
exists ( Boolean baseTypesEqual |
299
- ( baseTypesEqual = true implies equalTypes ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
352
+ ( baseTypesEqual = true implies equalTypesImpl ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
300
353
(
301
354
Config:: equalPointerTypes ( t1 , t2 , baseTypesEqual )
302
355
or
@@ -310,20 +363,20 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
310
363
// Note that this case is different from the above, in that we don't merely get the base
311
364
// type (as that could be a TypedefType that points to another SpecifiedType). We need to
312
365
// 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
314
367
Config:: equalSpecifiedTypes ( t1 , t2 , unspecifiedTypesEqual )
315
368
)
316
369
}
317
370
318
371
bindingset [ t1, t2]
319
372
private predicate equalFunctionTypes ( RelevantFunctionType t1 , RelevantFunctionType t2 ) {
320
373
exists ( Boolean returnTypeEqual , Boolean parameterTypesEqual |
321
- ( returnTypeEqual = true implies equalTypes ( t1 .getReturnType ( ) , t2 .getReturnType ( ) ) ) and
374
+ ( returnTypeEqual = true implies equalTypesImpl ( t1 .getReturnType ( ) , t2 .getReturnType ( ) ) ) and
322
375
(
323
376
parameterTypesEqual = true
324
377
implies
325
378
forall ( int i | exists ( [ t1 , t2 ] .getParameterType ( i ) ) |
326
- equalTypes ( t1 .getParameterType ( i ) , t2 .getParameterType ( i ) )
379
+ equalTypesImpl ( t1 .getParameterType ( i ) , t2 .getParameterType ( i ) )
327
380
)
328
381
) and
329
382
(
@@ -337,30 +390,52 @@ module TypeEquivalence<TypeEquivalenceSig Config, TypeSubset T> {
337
390
bindingset [ t1, t2]
338
391
private predicate equalTypedefTypes ( RelevantTypedefType t1 , RelevantTypedefType t2 ) {
339
392
exists ( Boolean baseTypesEqual |
340
- ( baseTypesEqual = true implies equalTypes ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
393
+ ( baseTypesEqual = true implies equalTypesImpl ( t1 .getBaseType ( ) , t2 .getBaseType ( ) ) ) and
341
394
Config:: equalTypedefTypes ( t1 , t2 , baseTypesEqual )
342
395
)
343
396
}
344
397
}
345
398
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
+
347
422
predicate equalReturnTypes ( FunctionDeclarationEntry f1 , FunctionDeclarationEntry f2 ) {
348
- TypeEquivalence< Config , FunctionSignatureType > :: equalTypes ( f1 .getType ( ) , f2 .getType ( ) )
423
+ TypeEquivalence< Config , interestedInReturnTypes / 2 > :: equalTypes ( f1 .getType ( ) , f2 .getType ( ) )
349
424
}
350
425
351
426
predicate equalParameterTypes ( FunctionDeclarationEntry f1 , FunctionDeclarationEntry f2 ) {
427
+ interestedInFunctions ( f1 , f2 ) and
352
428
f1 .getDeclaration ( ) = f2 .getDeclaration ( ) and
353
429
forall ( int i | exists ( [ f1 , f2 ] .getParameterDeclarationEntry ( i ) ) |
354
430
equalParameterTypesAt ( f1 , f2 , pragma [ only_bind_into ] ( i ) )
355
431
)
356
432
}
357
433
358
434
predicate 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 ( ) )
364
439
}
365
440
}
366
441
0 commit comments