Skip to content

Commit 982c597

Browse files
First pass on 17-12, 17-13, both facing extractor issues.
1 parent fb43031 commit 982c597

File tree

11 files changed

+502
-0
lines changed

11 files changed

+502
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* @id c/misra/function-addresses-should-address-operator
3+
* @name RULE-17-12: A function identifier should only be called with a parenthesized parameter list or used with a &
4+
* @description A function identifier should only be called with a parenthesized parameter list or
5+
* used with a & (address-of).
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-17-12
10+
* readability
11+
* external/misra/obligation/advisory
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.misra
16+
17+
abstract class AddressOfFunction extends Expr {
18+
abstract predicate isImplicitlyAddressed();
19+
20+
abstract string getFuncName();
21+
}
22+
23+
class FunctionTypeAccess extends FunctionAccess, AddressOfFunction {
24+
25+
predicate isImmediatelyParenthesized() {
26+
exists(ParenthesisExpr parens | parens.getExpr() = this)
27+
}
28+
29+
predicate isExplicitlyAddressed() {
30+
getParent() instanceof AddressOfExpr and
31+
not isImmediatelyParenthesized()
32+
}
33+
34+
override predicate isImplicitlyAddressed() {
35+
not isExplicitlyAddressed()
36+
}
37+
38+
override string getFuncName() {
39+
result = getTarget().getName()
40+
}
41+
}
42+
43+
/*
44+
class IndirectFunctionCall extends FunctionCall, AddressOfFunction {
45+
override predicate isImplicitlyAddressed() {
46+
getConversion+() instanceof ParenthesisExpr
47+
}
48+
49+
override string getFuncName() {
50+
result = getTarget().getName()
51+
}
52+
}
53+
*/
54+
55+
class MacroArgTakesFunction extends AddressOfFunction {
56+
MacroInvocation m;
57+
MacroArgTakesFunction() {
58+
m.getExpr() = this
59+
}
60+
61+
override predicate isImplicitlyAddressed() {
62+
any()
63+
}
64+
65+
string getProp() {
66+
result = m.getExpandedArgument(_)
67+
and this.get
68+
}
69+
70+
override string getFuncName() {
71+
result = "a macro argument"
72+
}
73+
74+
}
75+
76+
from AddressOfFunction funcAddr
77+
where
78+
not isExcluded(funcAddr, FunctionTypesPackage::functionAddressesShouldAddressOperatorQuery()) and
79+
//not funcAccess.isImmediatelyCalled() and
80+
//not funcAccess.isExplicitlyAddressed()
81+
funcAddr.isImplicitlyAddressed()
82+
select
83+
funcAddr, "The address of function " + funcAddr.getFuncName() + " is taken without the & operator."
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/**
2+
* @id c/misra/disallowed-function-type-qualifier
3+
* @name RULE-17-13: A function type shall not include any type qualifiers (const, volatile, restrict, or _Atomic)
4+
* @description The behavior of type qualifiers on a function type is undefined.
5+
* @kind problem
6+
* @precision very-high
7+
* @problem.severity error
8+
* @tags external/misra/id/rule-17-13
9+
* correctness
10+
* external/misra/obligation/required
11+
*/
12+
13+
import cpp
14+
import codingstandards.c.misra
15+
16+
//from DeclarationEntry decl, Type type //, Specifier specifier
17+
//where
18+
// not isExcluded(decl, FunctionTypesPackage::disallowedFunctionTypeQualifierQuery()) and
19+
// //decl.getType() instanceof FunctionPointerType and
20+
// //decl.getType().(FunctionPointerType).hasSpecifier(specifier)
21+
// (type = decl.getType().getUnderlyingType*()
22+
// or type = decl.getType())
23+
// and
24+
// //specifier = type.getASpecifier()
25+
// any()
26+
//select decl, type //, specifier // "The behavior of type qualifier " + specifier + " on a function type is undefined."
27+
28+
newtype TDeclaredFunction =
29+
TFunctionDeclaration(Declaration declaration)
30+
31+
abstract class DeclaredFunction extends TDeclaredFunction {
32+
abstract string toString();
33+
}
34+
35+
predicate isConstFunction(Type type) {
36+
(type.getASpecifier().getName() = "const"
37+
or type.isConst())
38+
and isFunctionType(type)
39+
or isConstFunction(type.getUnderlyingType())
40+
}
41+
42+
predicate isFunctionType(Type type) {
43+
type instanceof FunctionPointerType
44+
or isFunctionType(type.getUnderlyingType())
45+
}
46+
47+
predicate declaresConstFunction(DeclarationEntry entry) {
48+
(entry.getDeclaration().getASpecifier().getName() = "const"
49+
and isFunctionType(entry.getType()))
50+
or isConstFunction(entry.getType())
51+
}
52+
53+
class QualifiableRoutineType extends RoutineType, QualifiableType {
54+
override string explainQualifiers() {
55+
result = "func{"
56+
+ specifiersOf(this) + this.getReturnType().(QualifiableType).explainQualifiers()
57+
+ " ("
58+
+ paramString(0)
59+
+ ")}"
60+
}
61+
62+
string paramString(int i) {
63+
i = 0 and result = "" and not exists(this.getAParameterType())
64+
or
65+
(
66+
if i < max(int j | exists(this.getParameterType(j)))
67+
then
68+
// Not the last one
69+
result = this.getParameterType(i).(QualifiableType).explainQualifiers() + "," + this.paramString(i + 1)
70+
else
71+
// Last parameter
72+
result = this.getParameterType(i).(QualifiableType).explainQualifiers()
73+
)
74+
}
75+
}
76+
77+
class QualifiableIntType extends IntType, QualifiableType {
78+
override string explainQualifiers() {
79+
result = specifiersOf(this) + " " + this.toString()
80+
}
81+
}
82+
83+
class QualifiablePointerType extends PointerType, QualifiableType {
84+
override string explainQualifiers() {
85+
result = "{"
86+
+ specifiersOf(this)
87+
+ " pointer to "
88+
+ this.getBaseType().(QualifiableType).explainQualifiers()
89+
+ "}"
90+
}
91+
}
92+
93+
class QualifiableType extends Type {
94+
string explainQualifiers() {
95+
result = "Unimplemented explainQualifiers for type(s): " + concat(string s | s = getAQlClass() | s, ",")
96+
}
97+
}
98+
99+
class QualifiableTypedefType extends TypedefType, QualifiableType {
100+
override string explainQualifiers() {
101+
result = "{ typedef "
102+
+ specifiersOf(this)
103+
+ " "
104+
+ this.getBaseType().(QualifiableType).explainQualifiers()
105+
+ "}"
106+
}
107+
}
108+
109+
class QualifiableSpecifiedType extends SpecifiedType, QualifiableType {
110+
override string explainQualifiers() {
111+
result = "{"
112+
+ specifiersOf(this)
113+
+ " "
114+
+ this.getBaseType().(QualifiableType).explainQualifiers()
115+
+ "}"
116+
}
117+
}
118+
119+
string typeString(Type t) {
120+
//if
121+
// t instanceof CTypedefType
122+
// then result = t.(CTypedefType).explain() + "specs:" + specifiersOf(t.(CTypedefType).getBaseType()) + "/" + typeString(t.(CTypedefType).getBaseType())
123+
// else
124+
//result = concat(string s | s = t.getAQlClass() | s, ",")
125+
result = t.(QualifiableType).explainQualifiers()
126+
}
127+
128+
string specifiersOf(Type t) {
129+
result = concat(Specifier s | s = t.getASpecifier()| s.getName(), ", ")
130+
}
131+
132+
string declSpecifiersOf(Declaration d) {
133+
result = concat(Specifier s | s = d.getASpecifier()| s.getName(), ", ")
134+
}
135+
136+
string underlying(Type t) {
137+
exists(Type u | u = t.getUnderlyingType() | result = u.toString())
138+
or result = "[no underlying]"
139+
140+
}
141+
142+
from DeclarationEntry entry
143+
select entry, entry.getType(), typeString(entry.getType()), declSpecifiersOf(entry.getDeclaration()), specifiersOf(entry.getType())
144+
145+
//from Type t
146+
//where any()//isFunctionType(t)
147+
//select t, specifiersOf(t), underlying(t)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
| test.c:15:25:15:29 | func2 | The address of function func2 is taken without the & operator. |
2+
| test.c:16:27:16:31 | func3 | The address of function func3 is taken without the & operator. |
3+
| test.c:22:16:22:20 | func1 | The address of function func1 is taken without the & operator. |
4+
| test.c:38:5:38:9 | func1 | The address of function func1 is taken without the & operator. |
5+
| test.c:39:5:39:9 | func2 | The address of function func2 is taken without the & operator. |
6+
| test.c:47:7:47:11 | func1 | The address of function func1 is taken without the & operator. |
7+
| test.c:48:7:48:11 | func2 | The address of function func2 is taken without the & operator. |
8+
| test.c:57:15:57:19 | func1 | The address of function func1 is taken without the & operator. |
9+
| test.c:58:23:58:27 | func2 | The address of function func2 is taken without the & operator. |
10+
| test.c:59:15:59:19 | func1 | The address of function func1 is taken without the & operator. |
11+
| test.c:59:22:59:26 | func2 | The address of function func2 is taken without the & operator. |
12+
| test.c:67:13:67:17 | func1 | The address of function func1 is taken without the & operator. |
13+
| test.c:68:14:68:18 | func1 | The address of function func1 is taken without the & operator. |
14+
| test.c:69:14:69:18 | func1 | The address of function func1 is taken without the & operator. |
15+
| test.c:71:20:71:24 | func1 | The address of function func1 is taken without the & operator. |
16+
| test.c:72:20:72:24 | func1 | The address of function func1 is taken without the & operator. |
17+
| test.c:76:20:76:24 | func1 | The address of function func1 is taken without the & operator. |
18+
| test.c:77:20:77:24 | func1 | The address of function func1 is taken without the & operator. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-17-12/FunctionAddressesShouldAddressOperator.ql

c/misra/test/rules/RULE-17-12/test.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
void func1() {}
2+
void func2(int x, char* y) {}
3+
4+
typedef struct {} s;
5+
6+
int func3() {
7+
return 0;
8+
}
9+
10+
typedef void (*func_ptr_t1)();
11+
typedef void (*func_ptr_t2)(int x, char* y);
12+
typedef s (*func_ptr_t3)();
13+
14+
func_ptr_t1 func_ptr1 = &func1; // COMPLIANT
15+
func_ptr_t2 func_ptr2 = func2; // NON-COMPLIANT
16+
func_ptr_t3 func_ptr3 = &(func3); // NON-COMPLIANT
17+
18+
void take_func(func_ptr_t1 f1, func_ptr_t2 f2);
19+
20+
func_ptr_t1 returns_func(int x) {
21+
if (x == 0) {
22+
return func1; // NON-COMPLIANT
23+
} else if (x == 1) {
24+
return &func1; // COMPLIANT
25+
}
26+
27+
return returns_func(0); // COMPLIANT
28+
}
29+
30+
#define MACRO_IDENTITY(f) (f)
31+
#define MACRO_INVOKE_RISKY(f) (f())
32+
#define MACRO_INVOKE_IMPROVED(f) ((f)())
33+
34+
void test() {
35+
func1(); // COMPLIANT
36+
func2(1, "hello"); // COMPLIANT
37+
38+
func1; // NON-COMPLIANT
39+
func2; // NON-COMPLIANT
40+
41+
&func1; // COMPLIANT
42+
&func2; // COMPLIANT
43+
44+
(func1)(); // COMPLIANT
45+
(func2)(1, "hello"); // COMPLIANT
46+
47+
&(func1); // NON-COMPLIANT
48+
&(func2); // NON-COMPLIANT
49+
50+
(&func1)(); // COMPLIANT
51+
(&func2)(1, "hello"); // COMPLIANT
52+
53+
(func1()); // COMPLIANT
54+
(func2(1, "hello")); // COMPLIANT
55+
56+
take_func(&func1, &func2); // COMPLIANT
57+
take_func(func1, &func2); // NON-COMPLIANT
58+
take_func(&func1, func2); // NON-COMPLIANT
59+
take_func(func1, func2); // NON-COMPLIANT
60+
61+
returns_func(0); // COMPLIANT
62+
returns_func(0)(); // COMPLIANT
63+
(returns_func(0))(); // COMPLIANT
64+
65+
(void*) &func1; // COMPLIANT
66+
(void*) (&func1); // COMPLIANT
67+
(void*) func1; // NON-COMPLIANT
68+
(void*) (func1); // NON-COMPLIANT
69+
((void*) func1); // NON-COMPLIANT
70+
71+
MACRO_IDENTITY(func1); // NON-COMPLIANT
72+
MACRO_IDENTITY(func1)(); // NON-COMPLIANT
73+
MACRO_IDENTITY(&func1); // COMPLIANT
74+
MACRO_IDENTITY(&func1)(); // COMPLIANT
75+
76+
MACRO_INVOKE_RISKY(func3); // NON-COMPLIANT
77+
MACRO_INVOKE_IMPROVED(func3); // NON-COMPLIANT
78+
MACRO_INVOKE_IMPROVED(&func3); // COMPLIANT
79+
80+
// Function pointers are exempt from this rule.
81+
func_ptr1(); // COMPLIANT
82+
func_ptr2(1, "hello"); // COMPLIANT
83+
func_ptr1; // COMPLIANT
84+
func_ptr2; // COMPLIANT
85+
&func_ptr1; // COMPLIANT
86+
&func_ptr2; // COMPLIANT
87+
(func_ptr1)(); // COMPLIANT
88+
(func_ptr2)(1, "hello"); // COMPLIANT
89+
(*func_ptr1)(); // COMPLIANT
90+
(*func_ptr2)(1, "hello"); // COMPLIANT
91+
take_func(func_ptr1, func_ptr2); // COMPLIANT
92+
(void*) func_ptr1; // COMPLIANT
93+
(void*) &func_ptr1; // COMPLIANT
94+
(void*) (&func_ptr1); // COMPLIANT
95+
(void*) func_ptr1; // COMPLIANT
96+
(void*) (func_ptr1); // COMPLIANT
97+
((void*) func_ptr1); // COMPLIANT
98+
MACRO_IDENTITY(func_ptr1); // COMPLIANT
99+
MACRO_IDENTITY(func_ptr1)(); // COMPLIANT
100+
MACRO_IDENTITY(&func_ptr1); // COMPLIANT
101+
(*MACRO_IDENTITY(&func_ptr1))(); // COMPLIANT
102+
MACRO_INVOKE_RISKY(func_ptr3); // COMPLIANT
103+
MACRO_INVOKE_IMPROVED(func_ptr3); // COMPLIANT
104+
MACRO_INVOKE_IMPROVED(*&func_ptr3); // COMPLIANT
105+
106+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No expected results have yet been specified
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-17-13/DisallowedFunctionTypeQualifier.ql

0 commit comments

Comments
 (0)