|
| 1 | +/** |
| 2 | + * @id c/cert/do-not-compare-function-pointers-to-constant-values |
| 3 | + * @name EXP16-C: Do not compare function pointers to constant values |
| 4 | + * @description Comparing function pointers to a constant value is not reliable and likely indicates |
| 5 | + * a programmer error. |
| 6 | + * @kind problem |
| 7 | + * @precision very-high |
| 8 | + * @problem.severity error |
| 9 | + * @tags external/cert/id/exp16-c |
| 10 | + * correctness |
| 11 | + * external/cert/obligation/rule |
| 12 | + */ |
| 13 | + |
| 14 | +import cpp |
| 15 | +import codingstandards.c.cert |
| 16 | +import codingstandards.cpp.types.FunctionType |
| 17 | +import semmle.code.cpp.controlflow.IRGuards |
| 18 | + |
| 19 | +class FunctionExpr extends Expr { |
| 20 | + Element function; |
| 21 | + string funcName; |
| 22 | + |
| 23 | + FunctionExpr() { |
| 24 | + function = this.(FunctionAccess).getTarget() and |
| 25 | + funcName = "Function " + function.(Function).getName() |
| 26 | + or |
| 27 | + this.(VariableAccess).getUnderlyingType() instanceof FunctionType and |
| 28 | + function = this and |
| 29 | + funcName = "Function pointer variable " + this.(VariableAccess).getTarget().getName() |
| 30 | + or |
| 31 | + this.getUnderlyingType() instanceof FunctionType and |
| 32 | + not this instanceof FunctionAccess and |
| 33 | + not this instanceof VariableAccess and |
| 34 | + function = this and |
| 35 | + funcName = "Expression with function pointer type" |
| 36 | + } |
| 37 | + |
| 38 | + Element getFunction() { result = function } |
| 39 | + |
| 40 | + string getFuncName() { result = funcName } |
| 41 | +} |
| 42 | + |
| 43 | +abstract class EffectivelyComparison extends Element { |
| 44 | + abstract string getExplanation(); |
| 45 | + |
| 46 | + abstract FunctionExpr getFunctionExpr(); |
| 47 | +} |
| 48 | + |
| 49 | +class ExplicitComparison extends EffectivelyComparison, ComparisonOperation { |
| 50 | + Expr constantExpr; |
| 51 | + FunctionExpr funcExpr; |
| 52 | + |
| 53 | + ExplicitComparison() { |
| 54 | + funcExpr = getAnOperand() and |
| 55 | + constantExpr = getAnOperand() and |
| 56 | + exists(constantExpr.getValue()) and |
| 57 | + not funcExpr = constantExpr and |
| 58 | + not constantExpr.getExplicitlyConverted().getUnderlyingType() = |
| 59 | + funcExpr.getExplicitlyConverted().getUnderlyingType() |
| 60 | + } |
| 61 | + |
| 62 | + override string getExplanation() { result = "$@ compared to constant value." } |
| 63 | + |
| 64 | + override FunctionExpr getFunctionExpr() { result = funcExpr } |
| 65 | +} |
| 66 | + |
| 67 | +class ImplicitComparison extends EffectivelyComparison, GuardCondition { |
| 68 | + ImplicitComparison() { |
| 69 | + this instanceof FunctionExpr and |
| 70 | + not getParent() instanceof ComparisonOperation |
| 71 | + } |
| 72 | + |
| 73 | + override string getExplanation() { result = "$@ undergoes implicit constant comparison." } |
| 74 | + |
| 75 | + override FunctionExpr getFunctionExpr() { result = this } |
| 76 | +} |
| 77 | + |
| 78 | +from EffectivelyComparison comparison, FunctionExpr funcExpr, Element function, string funcName |
| 79 | +where |
| 80 | + not isExcluded(comparison, |
| 81 | + Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and |
| 82 | + funcExpr = comparison.getFunctionExpr() and |
| 83 | + function = funcExpr.getFunction() and |
| 84 | + funcName = funcExpr.getFuncName() |
| 85 | +select comparison, comparison.getExplanation(), function, funcName |
| 86 | +//from |
| 87 | +// EqualityOperation equality, FunctionExpr funcExpr, Element function, string funcName, |
| 88 | +// Expr constantExpr |
| 89 | +//where |
| 90 | +// not isExcluded(equality, Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and |
| 91 | +// funcExpr = equality.getAnOperand() and |
| 92 | +// constantExpr = equality.getAnOperand() and |
| 93 | +// exists(constantExpr.getValue()) and |
| 94 | +// function = funcExpr.getFunction() and |
| 95 | +// funcName = funcExpr.getFuncName() and |
| 96 | +// constantExpr.getFullyConverted().getUnderlyingType() = |
| 97 | +// funcExpr.getFullyConverted().getUnderlyingType() |
| 98 | +//select equality, |
| 99 | +// "Pointer to function $@ compared to constant value." + |
| 100 | +// constantExpr.getFullyConverted().getUnderlyingType().explain() + " / " + |
| 101 | +// funcExpr.getFullyConverted().getUnderlyingType().explain(), function, funcName |
0 commit comments