Skip to content

Commit f4e10dc

Browse files
authored
Merge pull request #784 from github/michaelrfairhurst/implement-deadcode-2-unused-object-definitions
Implement RULE-2-8, project should not contain unused object definitions
2 parents 8736ca7 + 3566e0f commit f4e10dc

22 files changed

+958
-17
lines changed

c/misra/src/codeql-suites/misra-c-default.qls

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
- exclude:
88
tags contain:
99
- external/misra/audit
10+
- external/misra/strict
1011
- external/misra/default-disabled
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
- description: MISRA C 2012 (Strict)
2+
- qlpack: codeql/misra-c-coding-standards
3+
- include:
4+
kind:
5+
- problem
6+
- path-problem
7+
tags contain:
8+
- external/misra/strict
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @id c/misra/unused-object-definition
3+
* @name RULE-2-8: A project should not contain unused object definitions
4+
* @description Object definitions which are unused should be removed.
5+
* @kind problem
6+
* @precision very-high
7+
* @problem.severity recommendation
8+
* @tags external/misra/id/rule-2-8
9+
* maintainability
10+
* performance
11+
* external/misra/c/2012/amendment4
12+
* external/misra/obligation/advisory
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.cpp.deadcode.UnusedObjects
18+
19+
from ReportDeadObject report
20+
where
21+
not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionQuery()) and
22+
not report.hasAttrUnused()
23+
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
24+
report.getOptionalPlaceholderMessage()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @id c/misra/unused-object-definition-strict
3+
* @name RULE-2-8: A project should not contain '__attribute__((unused))' object definitions
4+
* @description A strict query which reports all unused object definitions with
5+
* '__attribute__((unused))'.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity recommendation
9+
* @tags external/misra/id/rule-2-8
10+
* maintainability
11+
* performance
12+
* external/misra/c/2012/amendment4
13+
* external/misra/c/strict
14+
* external/misra/obligation/advisory
15+
*/
16+
17+
import cpp
18+
import codingstandards.c.misra
19+
import codingstandards.cpp.deadcode.UnusedObjects
20+
21+
from ReportDeadObject report
22+
where
23+
not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionStrictQuery()) and
24+
report.hasAttrUnused()
25+
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
26+
report.getOptionalPlaceholderMessage()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
| test.c:6:5:6:6 | definition of g2 | Unused object 'g2'. | test.c:6:5:6:6 | test.c:6:5:6:6 | (ignored) |
2+
| test.c:9:5:9:6 | definition of g3 | Unused object 'g3'. | test.c:9:5:9:6 | test.c:9:5:9:6 | (ignored) |
3+
| test.c:20:7:20:8 | definition of l2 | Unused object 'l2'. | test.c:20:7:20:8 | test.c:20:7:20:8 | (ignored) |
4+
| test.c:27:7:27:8 | definition of l5 | Unused object 'l5'. | test.c:27:7:27:8 | test.c:27:7:27:8 | (ignored) |
5+
| test.c:37:10:37:11 | definition of g5 | Unused object 'g5'. | test.c:37:10:37:11 | test.c:37:10:37:11 | (ignored) |
6+
| test.c:45:9:45:10 | definition of g6 | Unused object 'g6'. | test.c:45:9:45:10 | test.c:45:9:45:10 | (ignored) |
7+
| test.c:51:5:51:6 | definition of g7 | Unused object 'g7'. | test.c:51:5:51:6 | test.c:51:5:51:6 | (ignored) |
8+
| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:60:1:60:34 | test.c:60:1:60:34 | ONLY_DEF_VAR |
9+
| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:73:16:73:17 | test.c:73:16:73:17 | l1 |
10+
| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | test.c:77:1:82:3 | (ignored) |
11+
| test.c:119:11:119:13 | definition of g10 | Unused object 'g10'. | test.c:119:11:119:13 | test.c:119:11:119:13 | (ignored) |
12+
| test.c:124:13:124:14 | definition of l2 | Unused object 'l2'. | test.c:124:13:124:14 | test.c:124:13:124:14 | (ignored) |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-2-8/UnusedObjectDefinition.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| test.c:87:29:87:30 | definition of g8 | Unused object 'g8'. | test.c:87:29:87:30 | test.c:87:29:87:30 | (ignored) |
2+
| test.c:92:3:92:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:88:1:88:70 | test.c:88:1:88:70 | ONLY_DEF_ATTR_UNUSED_VAR |
3+
| test.c:96:1:99:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:101:28:101:29 | test.c:101:28:101:29 | l1 |
4+
| test.c:106:1:111:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:106:1:111:3 | test.c:106:1:111:3 | (ignored) |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-2-8/UnusedObjectDefinitionStrict.ql

c/misra/test/rules/RULE-2-8/test.c

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Not a definition, only a declaration:
2+
extern int g1; // COMPLIANT
3+
4+
// Both declared + defined:
5+
extern int g2; // COMPLIANT
6+
int g2 = 1; // NON_COMPLIANT
7+
8+
// Definition is only declaration:
9+
int g3 = 1; // NON_COMPLIANT
10+
11+
// Definition, but value is required for program to compile:
12+
int g4 = 1; // COMPLIANT
13+
void f1() { g4; }
14+
15+
// Local variables:
16+
void f2() {
17+
int l1; // COMPLIANT
18+
l1;
19+
20+
int l2; // NON-COMPLIANT
21+
22+
// Value is required for the program to compile:
23+
int l3; // COMPLIANT
24+
sizeof(l3);
25+
26+
int l4, // COMPLIANT
27+
l5; // NON-COMPLIANT
28+
l4;
29+
}
30+
31+
// Struct fields are not objects:
32+
struct s {
33+
int x; // COMPLIANT
34+
};
35+
36+
// Declaration of type struct is an object:
37+
struct s g5; // NON-COMPLIANT
38+
39+
// Struct fields are not objects:
40+
union u {
41+
int x; // COMPLIANT
42+
};
43+
44+
// Declaration of type union is an object:
45+
union u g6; // NON-COMPLIANT
46+
47+
// Typedefs are not objects:
48+
typedef int td1; // COMPLIANT
49+
50+
// Declaration of typedef type object:
51+
td1 g7; // NON-COMPLIANT
52+
53+
// Function parameters are not objects:
54+
void f3(int p) {} // COMPLIANT
55+
56+
// Function type parameters are not objects:
57+
typedef int td2(int x); // COMPLIANT
58+
59+
// Macros that define unused vars tests:
60+
#define ONLY_DEF_VAR(x) int x = 0;
61+
void f4() {
62+
ONLY_DEF_VAR(l1); // COMPLIANT
63+
l1;
64+
ONLY_DEF_VAR(l2); // NON-COMPLIANT
65+
}
66+
67+
// NON-COMPLIANT
68+
#define ALSO_DEF_VAR(x) \
69+
int x = 0; \
70+
while (1) \
71+
;
72+
void f5() {
73+
ALSO_DEF_VAR(l1); // COMPLIANT
74+
ALSO_DEF_VAR(l2); // COMPLIANT
75+
}
76+
77+
#define DEF_UNUSED_INNER_VAR() \
78+
{ \
79+
int _v = 0; \
80+
while (1) \
81+
; \
82+
} // NON-COMPLIANT
83+
void f6() {
84+
DEF_UNUSED_INNER_VAR(); // COMPLIANT
85+
}
86+
87+
__attribute__((unused)) int g8 = 1; // NON-COMPLIANT
88+
#define ONLY_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0;
89+
void f7() {
90+
ONLY_DEF_ATTR_UNUSED_VAR(l1); // COMPLIANT
91+
l1;
92+
ONLY_DEF_ATTR_UNUSED_VAR(l2); // NON-COMPLIANT
93+
}
94+
95+
// NON-COMPLIANT
96+
#define ALSO_DEF_ATTR_UNUSED_VAR(x) \
97+
__attribute__((unused)) int x = 0; \
98+
while (1) \
99+
;
100+
void f8() {
101+
ALSO_DEF_ATTR_UNUSED_VAR(l1); // COMPLIANT
102+
ALSO_DEF_ATTR_UNUSED_VAR(l2); // COMPLIANT
103+
}
104+
105+
// NON-COMPLIANT
106+
#define DEF_ATTR_UNUSED_INNER_VAR() \
107+
{ \
108+
__attribute__((unused)) int _v = 0; \
109+
while (1) \
110+
; \
111+
}
112+
113+
void f9() {
114+
DEF_ATTR_UNUSED_INNER_VAR(); // COMPLIANT
115+
}
116+
117+
// Const variable tests:
118+
const int g9 = 1; // COMPLIANT
119+
const int g10 = 1; // NON-COMPLIANT
120+
121+
void f10() {
122+
g9;
123+
const int l1 = 1; // COMPLIANT
124+
const int l2 = 1; // NON-COMPLIANT
125+
l1;
126+
}
127+
128+
// Side effects should not disable this rule:
129+
void f11() {
130+
int l1 = 1; // COMPLIANT
131+
int l2 = l1++; // COMPLIANT
132+
l2;
133+
}

cpp/common/src/codingstandards/cpp/AlertReporting.qll

+25-3
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,46 @@ module MacroUnwrapper<ResultType ResultElement> {
1818
}
1919

2020
/**
21-
* Gets the primary macro that generated the result element.
21+
* Gets the primary macro invocation that generated the result element.
2222
*/
23-
Macro getPrimaryMacro(ResultElement re) {
23+
MacroInvocation getPrimaryMacroInvocation(ResultElement re) {
2424
exists(MacroInvocation mi |
2525
mi = getAMacroInvocation(re) and
2626
// No other more specific macro that expands to element
2727
not exists(MacroInvocation otherMi |
2828
otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi
2929
) and
30-
result = mi.getMacro()
30+
result = mi
3131
)
3232
}
3333

34+
/**
35+
* Gets the primary macro that generated the result element.
36+
*/
37+
Macro getPrimaryMacro(ResultElement re) { result = getPrimaryMacroInvocation(re).getMacro() }
38+
3439
/**
3540
* If a result element is expanded from a macro invocation, then return the "primary" macro that
3641
* generated the element, otherwise return the element itself.
3742
*/
3843
Element unwrapElement(ResultElement re) {
3944
if exists(getPrimaryMacro(re)) then result = getPrimaryMacro(re) else result = re
4045
}
46+
47+
/* Final class so we can extend it */
48+
final private class FinalMacroInvocation = MacroInvocation;
49+
50+
/* A macro invocation that expands to create a `ResultElement` */
51+
class ResultMacroExpansion extends FinalMacroInvocation {
52+
ResultElement re;
53+
54+
ResultMacroExpansion() { re = getAnExpandedElement() }
55+
56+
ResultElement getResultElement() { result = re }
57+
}
58+
59+
/* The most specific macro invocation that expands to create this `ResultElement`. */
60+
class PrimaryMacroExpansion extends ResultMacroExpansion {
61+
PrimaryMacroExpansion() { this = getPrimaryMacroInvocation(re) }
62+
}
4163
}

0 commit comments

Comments
 (0)