Skip to content

Commit 2fad698

Browse files
authoredMar 31, 2025··
Merge pull request #871 from github/michaelrfairhurst/implement-essential-types2-package
Implement EssentialTypes2 package
2 parents 0fd4496 + ae557d9 commit 2fad698

12 files changed

+1163
-0
lines changed
 

Diff for: ‎c/common/src/codingstandards/c/TgMath.qll

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import cpp
2+
3+
private string getATgMathMacroName(boolean allowComplex) {
4+
allowComplex = true and
5+
result =
6+
[
7+
"acos", "acosh", "asin", "asinh", "atan", "atanh", "carg", "cimag", "conj", "cos", "cosh",
8+
"cproj", "creal", "exp", "fabs", "log", "pow", "sin", "sinh", "sqrt", "tan", "tanh"
9+
]
10+
or
11+
allowComplex = false and
12+
result =
13+
[
14+
"atan2", "cbrt", "ceil", "copysign", "erf", "erfc", "exp2", "expm1", "fdim", "floor", "fma",
15+
"fmax", "fmin", "fmod", "frexp", "hypot", "ilogb", "ldexp", "lgamma", "llrint", "llround",
16+
"log10", "log1p", "log2", "logb", "lrint", "lround", "nearbyint", "nextafter", "nexttoward",
17+
"remainder", "remquo", "rint", "round", "scalbn", "scalbln", "tgamma", "trunc",
18+
]
19+
}
20+
21+
private predicate hasOutputArgument(string macroName, int index) {
22+
macroName = "frexp" and index = 1
23+
or
24+
macroName = "remquo" and index = 2
25+
}
26+
27+
class TgMathInvocation extends MacroInvocation {
28+
Call call;
29+
boolean allowComplex;
30+
31+
TgMathInvocation() {
32+
this.getMacro().getName() = getATgMathMacroName(allowComplex) and
33+
call = getBestCallInExpansion(this)
34+
}
35+
36+
Expr getOperandArgument(int i) {
37+
result = call.getArgument(i) and
38+
not hasOutputArgument(call.getTarget().getName(), i)
39+
}
40+
41+
int getNumberOfOperandArguments() {
42+
result = call.getNumberOfArguments() - count(int i | hasOutputArgument(getMacroName(), i))
43+
}
44+
45+
Expr getAnOperandArgument() { result = getOperandArgument(_) }
46+
47+
predicate allowsComplex() { allowComplex = true }
48+
}
49+
50+
private Call getACallInExpansion(MacroInvocation mi) { result = mi.getAnExpandedElement() }
51+
52+
private Call getNameMatchedCallInExpansion(MacroInvocation mi) {
53+
result = getACallInExpansion(mi) and result.getTarget().getName() = mi.getMacroName()
54+
}
55+
56+
private Call getBestCallInExpansion(MacroInvocation mi) {
57+
count(getACallInExpansion(mi)) = 1 and result = getACallInExpansion(mi)
58+
or
59+
count(getNameMatchedCallInExpansion(mi)) = 1 and result = getNameMatchedCallInExpansion(mi)
60+
or
61+
count(getNameMatchedCallInExpansion(mi)) > 1 and
62+
result = rank[1](Call c | c = getACallInExpansion(mi) | c order by c.getTarget().getName())
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @id c/misra/tg-math-argument-with-invalid-essential-type
3+
* @name RULE-21-22: All operand arguments to type-generic macros in <tgmath.h> shall have an appropriate essential type
4+
* @description All operand arguments to any type-generic macros in <tgmath.h> shall have an
5+
* appropriate essential type.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-21-22
10+
* correctness
11+
* external/misra/c/2012/amendment3
12+
* external/misra/obligation/mandatory
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.c.TgMath
18+
import codingstandards.c.misra.EssentialTypes
19+
20+
EssentialTypeCategory getAnAllowedEssentialTypeCategory(TgMathInvocation call) {
21+
result = EssentiallySignedType()
22+
or
23+
result = EssentiallyUnsignedType()
24+
or
25+
result = EssentiallyFloatingType(Real())
26+
or
27+
call.allowsComplex() and
28+
result = EssentiallyFloatingType(Complex())
29+
}
30+
31+
string getAllowedTypesString(TgMathInvocation call) {
32+
if call.allowsComplex()
33+
then result = "essentially signed, unsigned, or floating type"
34+
else result = "essentially signed, unsigned, or real floating type"
35+
}
36+
37+
from TgMathInvocation call, Expr arg, int argIndex, Type type, EssentialTypeCategory category
38+
where
39+
not isExcluded(call, EssentialTypes2Package::tgMathArgumentWithInvalidEssentialTypeQuery()) and
40+
arg = call.getOperandArgument(argIndex) and
41+
type = getEssentialType(arg) and
42+
category = getEssentialTypeCategory(type) and
43+
not category = getAnAllowedEssentialTypeCategory(call)
44+
select arg,
45+
"Argument " + (argIndex + 1) + " provided to type-generic macro '" + call.getMacroName() +
46+
"' has " + category.toString().toLowerCase() + ", which is not " + getAllowedTypesString(call) +
47+
"."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @id c/misra/tg-math-arguments-with-differing-standard-type
3+
* @name RULE-21-23: Operand arguments for an invocation of a type-generic macro shall have the same standard type
4+
* @description All operand arguments to any multi-argument type-generic macros in <tgmath.h> shall
5+
* have the same standard type.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-21-23
10+
* correctness
11+
* external/misra/c/2012/amendment3
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.c.TgMath
18+
19+
string argTypesString(TgMathInvocation call, int i) {
20+
exists(string typeStr |
21+
typeStr = getEffectiveStandardType(call.getOperandArgument(i)).toString() and
22+
(
23+
i = 0 and result = typeStr
24+
or
25+
i > 0 and result = argTypesString(call, i - 1) + ", " + typeStr
26+
)
27+
)
28+
}
29+
30+
/**
31+
* If the range of values can be represented as a signed int, it is promoted to signed int.
32+
*
33+
* A value may also promote to unsigned int but only if `int` cannot represent the range of
34+
* values. Which basically means only an `unsigned int` promotes to `unsigned int`, so we don't
35+
* need to do anything in this case.
36+
*
37+
* An unsigned int bitfield with fewer than 32 bits is promoted to `int`.
38+
*/
39+
predicate promotesToSignedInt(Expr e) {
40+
exists(int intBits, int intBytes |
41+
intBytes = any(IntType t).getSize() and
42+
intBits = intBytes * 8 and
43+
(
44+
e.(FieldAccess).getTarget().(BitField).getNumBits() < intBits
45+
or
46+
e.getUnderlyingType().(IntegralType).getSize() < intBytes
47+
)
48+
)
49+
}
50+
51+
Type getPromotedType(Expr e) {
52+
if promotesToSignedInt(e) then result.(IntType).isSigned() else result = e.getUnderlyingType()
53+
}
54+
55+
Type canonicalize(Type type) {
56+
if type instanceof IntegralType
57+
then result = type.(IntegralType).getCanonicalArithmeticType()
58+
else result = type
59+
}
60+
61+
Type getEffectiveStandardType(Expr e) {
62+
result = canonicalize(getPromotedType(e.getExplicitlyConverted()))
63+
}
64+
65+
from TgMathInvocation call, Type firstType
66+
where
67+
not isExcluded(call, EssentialTypes2Package::tgMathArgumentsWithDifferingStandardTypeQuery()) and
68+
firstType = getEffectiveStandardType(call.getAnOperandArgument()) and
69+
not forall(Expr arg | arg = call.getAnOperandArgument() |
70+
firstType = getEffectiveStandardType(arg)
71+
)
72+
select call,
73+
"Call to type-generic macro '" + call.getMacroName() +
74+
"' has arguments with differing standard types (" +
75+
argTypesString(call, call.getNumberOfOperandArguments() - 1) + ")."

0 commit comments

Comments
 (0)
Please sign in to comment.