Skip to content

Commit ad55446

Browse files
Merge remote-tracking branch 'origin/main' into michaelrfairhurt/add-additional-cert-rules
2 parents 64ad8fb + eedca61 commit ad55446

20 files changed

+1320
-1
lines changed

amendments.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language,standard,amendment,rule_id,supportable,implementation_category,implemented,difficulty
22
c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,Yes,Easy
33
c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,Yes,Easy
4-
c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,No,Import
4+
c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,Yes,Import
55
c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,Yes,Easy
66
c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,Yes,Easy
77
c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,Yes,Easy
+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,43 @@
1+
/**
2+
* @id c/misra/low-precision-periodic-trigonometric-function-call
3+
* @name DIR-4-11: The validity of values passed to trigonometric functions shall be checked
4+
* @description Trigonometric periodic functions have significantly less precision when called with
5+
* large floating-point values.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity warning
9+
* @tags external/misra/id/dir-4-11
10+
* correctness
11+
* external/misra/c/2012/third-edition-first-revision
12+
* external/misra/c/2012/amendment3
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.misra
18+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
19+
20+
float getMaxAllowedAbsoluteValue(FloatingPointType t, string description) {
21+
if t.getSize() <= 4
22+
then (
23+
// Per MISRA, assume k=1 for float types.
24+
result = 3.15 and description = "pi"
25+
) else (
26+
// Allow k=10 for doubles, as the standard allows for a larger range depending on the
27+
// implementation, application, and precision goals.
28+
result = 10 * 3.15 and description = "10 * pi"
29+
)
30+
}
31+
32+
from FunctionCall fc, Expr argument, float maxValue, float maxAllowedValue, string maxAllowedStr
33+
where
34+
not isExcluded(fc, ContractsPackage::lowPrecisionPeriodicTrigonometricFunctionCallQuery()) and
35+
fc.getTarget().getName() = ["sin", "cos", "tan"] and
36+
argument = fc.getArgument(0) and
37+
maxValue = rank[1](float bound | bound = [lowerBound(argument), upperBound(argument)].abs()) and
38+
maxAllowedValue = getMaxAllowedAbsoluteValue(argument.getType(), maxAllowedStr) and
39+
maxValue > maxAllowedValue
40+
select fc,
41+
"Call to periodic trigonometric function " + fc.getTarget().getName() +
42+
" with maximum argument absolute value of " + maxValue.toString() +
43+
", which exceeds the recommended " + "maximum of " + maxAllowedStr + "."
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) + ")."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
| test.c:32:5:32:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. |
2+
| test.c:33:5:33:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. |
3+
| test.c:34:5:34:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. |
4+
| test.c:38:5:38:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. |
5+
| test.c:39:5:39:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. |
6+
| test.c:40:5:40:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. |
7+
| test.c:49:5:49:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. |
8+
| test.c:50:5:50:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. |
9+
| test.c:51:5:51:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. |
10+
| test.c:52:5:52:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. |
11+
| test.c:53:5:53:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. |
12+
| test.c:54:5:54:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. |
13+
| test.c:55:5:55:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. |
14+
| test.c:56:5:56:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. |
15+
| test.c:57:5:57:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. |
16+
| test.c:58:5:58:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. |
17+
| test.c:59:5:59:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. |
18+
| test.c:60:5:60:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql

c/misra/test/rules/DIR-4-11/test.c

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include <math.h>
2+
void f(int x) {
3+
float f1 = 0.0f;
4+
double d1 = 0.0f;
5+
sin(f1); // COMPLIANT
6+
cos(f1); // COMPLIANT
7+
tan(f1); // COMPLIANT
8+
sin(d1); // COMPLIANT
9+
cos(d1); // COMPLIANT
10+
tan(d1); // COMPLIANT
11+
12+
if (x < 10) {
13+
f1 += 3.14;
14+
d1 += 3.14;
15+
sin(f1); // COMPLIANT
16+
cos(f1); // COMPLIANT
17+
tan(f1); // COMPLIANT
18+
sin(d1); // COMPLIANT
19+
cos(d1); // COMPLIANT
20+
tan(d1); // COMPLIANT
21+
sin(-f1); // COMPLIANT
22+
cos(-f1); // COMPLIANT
23+
tan(-f1); // COMPLIANT
24+
sin(-d1); // COMPLIANT
25+
cos(-d1); // COMPLIANT
26+
tan(-d1); // COMPLIANT
27+
}
28+
29+
if (x < 20) {
30+
f1 = 3.14 * 10;
31+
d1 = 3.14 * 10;
32+
sin(f1); // NON-COMPLIANT
33+
cos(f1); // NON-COMPLIANT
34+
tan(f1); // NON-COMPLIANT
35+
sin(d1); // COMPLIANT
36+
cos(d1); // COMPLIANT
37+
tan(d1); // COMPLIANT
38+
sin(-f1); // NON-COMPLIANT
39+
cos(-f1); // NON-COMPLIANT
40+
tan(-f1); // NON-COMPLIANT
41+
sin(-d1); // COMPLIANT
42+
cos(-d1); // COMPLIANT
43+
tan(-d1); // COMPLIANT
44+
}
45+
46+
if (x < 30) {
47+
f1 = 3.14 * 100;
48+
d1 = 3.14 * 100;
49+
sin(f1); // NON-COMPLIANT
50+
cos(f1); // NON-COMPLIANT
51+
tan(f1); // NON-COMPLIANT
52+
sin(d1); // NON-COMPLIANT
53+
cos(d1); // NON-COMPLIANT
54+
tan(d1); // NON-COMPLIANT
55+
sin(-f1); // NON-COMPLIANT
56+
cos(-f1); // NON-COMPLIANT
57+
tan(-f1); // NON-COMPLIANT
58+
sin(-d1); // NON-COMPLIANT
59+
cos(-d1); // NON-COMPLIANT
60+
tan(-d1); // NON-COMPLIANT
61+
}
62+
}

0 commit comments

Comments
 (0)