Skip to content

Commit 06351f5

Browse files
Try forcing top-down pairwise comparison
1 parent 4825774 commit 06351f5

File tree

1 file changed

+63
-75
lines changed

1 file changed

+63
-75
lines changed

cpp/common/src/codingstandards/cpp/types/Compatible.qll

Lines changed: 63 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
235235
module 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

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy