Skip to content

Commit bdd3865

Browse files
authored
Merge branch 'main' into codeql/upgrade-to-2.16.6
2 parents f718e2a + 1566129 commit bdd3865

24 files changed

+410
-57
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
11
import cpp
2+
import codingstandards.cpp.Pointers
23
import codingstandards.cpp.UndefinedBehavior
34

45
/**
56
* Library for modeling undefined behavior.
67
*/
78
abstract class CUndefinedBehavior extends UndefinedBehavior { }
89

10+
/**
11+
* A function which has the signature - but not the name - of a main function.
12+
*/
913
class C99MainFunction extends Function {
1014
C99MainFunction() {
1115
this.getNumberOfParameters() = 2 and
12-
this.getType() instanceof IntType and
13-
this.getParameter(0).getType() instanceof IntType and
14-
this.getParameter(1).getType().(PointerType).getBaseType().(PointerType).getBaseType()
15-
instanceof CharType
16+
this.getType().getUnderlyingType() instanceof IntType and
17+
this.getParameter(0).getType().getUnderlyingType() instanceof IntType and
18+
this.getParameter(1)
19+
.getType()
20+
.getUnderlyingType()
21+
.(UnspecifiedPointerOrArrayType)
22+
.getBaseType()
23+
.(UnspecifiedPointerOrArrayType)
24+
.getBaseType() instanceof CharType
1625
or
1726
this.getNumberOfParameters() = 0 and
18-
this.getType() instanceof VoidType
27+
// Must be explicitly declared as `int main(void)`.
28+
this.getADeclarationEntry().hasVoidParamList() and
29+
this.getType().getUnderlyingType() instanceof IntType
1930
}
2031
}
2132

2233
class CUndefinedMainDefinition extends CUndefinedBehavior, Function {
2334
CUndefinedMainDefinition() {
2435
// for testing purposes, we use the prefix ____codeql_coding_standards`
25-
(this.getName() = "main" or this.getName().indexOf("____codeql_coding_standards") = 0) and
36+
(this.getName() = "main" or this.getName().indexOf("____codeql_coding_standards_main") = 0) and
2637
not this instanceof C99MainFunction
2738
}
2839

2940
override string getReason() {
3041
result =
31-
"The behavior of the program is undefined because the main function is not defined according to the C standard."
42+
"main function may trigger undefined behavior because it is not in one of the formats specified by the C standard."
3243
}
3344
}

c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ import codingstandards.c.UndefinedBehavior
1818

1919
from CUndefinedBehavior c
2020
where not isExcluded(c, Language3Package::occurrenceOfUndefinedBehaviorQuery())
21-
select c, "May result in undefined behavior."
21+
select c, c.getReason()

c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql

+84-8
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,56 @@
1515

1616
import cpp
1717
import codingstandards.c.misra
18+
import codingstandards.cpp.Macro
19+
import codingstandards.cpp.Includes
20+
import codingstandards.cpp.PreprocessorDirective
1821

19-
from Macro m, Macro m2
22+
/**
23+
* Gets a top level element that this macro is expanded to, e.g. an element which does not also have
24+
* an enclosing element in the macro.
25+
*/
26+
Element getATopLevelElement(MacroInvocation mi) {
27+
result = mi.getAnExpandedElement() and
28+
not result.getEnclosingElement() = mi.getAnExpandedElement() and
29+
not result instanceof Conversion
30+
}
31+
32+
/**
33+
* Gets a link target that this macro is expanded in.
34+
*/
35+
LinkTarget getALinkTarget(Macro m) {
36+
exists(MacroInvocation mi, Element e |
37+
mi = m.getAnInvocation() and
38+
e = getATopLevelElement(mi)
39+
|
40+
result = e.(Expr).getEnclosingFunction().getALinkTarget()
41+
or
42+
result = e.(Stmt).getEnclosingFunction().getALinkTarget()
43+
or
44+
exists(GlobalOrNamespaceVariable g |
45+
result = g.getALinkTarget() and
46+
g = e.(Expr).getEnclosingDeclaration()
47+
)
48+
)
49+
}
50+
51+
/**
52+
* Holds if the m1 and m2 are unconditionally included from a common file.
53+
*
54+
* Extracted out for performance reasons - otherwise the call to determine the file path for the
55+
* message was specializing the calls to `getAnUnconditionallyIncludedFile*(..)` and causing
56+
* slow performance.
57+
*/
58+
bindingset[m1, m2]
59+
pragma[inline_late]
60+
private predicate isIncludedUnconditionallyFromCommonFile(Macro m1, Macro m2) {
61+
exists(File f |
62+
getAnUnconditionallyIncludedFile*(f) = m1.getFile() and
63+
getAnUnconditionallyIncludedFile*(f) = m2.getFile()
64+
)
65+
}
66+
67+
from Macro m, Macro m2, string message
2068
where
2169
not isExcluded(m, Declarations1Package::macroIdentifiersNotDistinctQuery()) and
2270
not m = m2 and
@@ -25,12 +73,40 @@ where
2573
//C90 states the first 31 characters of macro identifiers are significant and is not currently considered by this rule
2674
//ie an identifier differing on the 32nd character would be indistinct for C90 but distinct for C99
2775
//and is currently not reported by this rule
28-
if m.getName().length() >= 64
29-
then m.getName().prefix(63) = m2.getName().prefix(63)
30-
else m.getName() = m2.getName()
76+
if m.getName().length() >= 64 and not m.getName() = m2.getName()
77+
then (
78+
m.getName().prefix(63) = m2.getName().prefix(63) and
79+
message =
80+
"Macro identifer " + m.getName() + " is nondistinct in first 63 characters, compared to $@."
81+
) else (
82+
m.getName() = m2.getName() and
83+
message =
84+
"Definition of macro " + m.getName() +
85+
" is not distinct from alternative definition of $@ in " +
86+
m2.getLocation().getFile().getRelativePath() + "."
87+
)
3188
) and
3289
//reduce double report since both macros are in alert, arbitrary ordering
33-
m.getLocation().getStartLine() >= m2.getLocation().getStartLine()
34-
select m,
35-
"Macro identifer " + m.getName() + " is nondistinct in first 63 characters, compared to $@.", m2,
36-
m2.getName()
90+
m.getLocation().getStartLine() >= m2.getLocation().getStartLine() and
91+
// Not within an #ifndef MACRO_NAME
92+
not exists(PreprocessorIfndef ifBranch |
93+
m.getAGuard() = ifBranch or
94+
m2.getAGuard() = ifBranch
95+
|
96+
ifBranch.getHead() = m.getName()
97+
) and
98+
// Must be included unconditionally from the same file, otherwise m1 may not be defined
99+
// when m2 is defined
100+
isIncludedUnconditionallyFromCommonFile(m, m2) and
101+
// Macros can't be mutually exclusive
102+
not mutuallyExclusiveBranchDirectiveMacros(m, m2) and
103+
not mutuallyExclusiveBranchDirectiveMacros(m2, m) and
104+
// If at least one invocation exists for at least one of the macros, then they must share a link
105+
// target - i.e. must both be expanded in the same context
106+
(
107+
(exists(m.getAnInvocation()) and exists(m2.getAnInvocation()))
108+
implies
109+
// Must share a link target - e.g. must both be expanded in the same context
110+
getALinkTarget(m) = getALinkTarget(m2)
111+
)
112+
select m, message, m2, m2.getName()

c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql

+49-24
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,54 @@ import cpp
1818
import codingstandards.c.misra
1919
import codingstandards.cpp.Pointers
2020
import codingstandards.cpp.SideEffect
21+
import codingstandards.cpp.alertreporting.HoldsForAllCopies
2122

22-
from Variable ptr, PointerOrArrayType type
23+
class NonConstPointerVariableCandidate extends Variable {
24+
NonConstPointerVariableCandidate() {
25+
// Ignore parameters in functions without bodies
26+
(this instanceof Parameter implies exists(this.(Parameter).getFunction().getBlock())) and
27+
// Ignore variables in functions that use ASM commands
28+
not exists(AsmStmt a |
29+
a.getEnclosingFunction() = this.(LocalScopeVariable).getFunction()
30+
or
31+
// In a type declared locally
32+
this.(Field).getDeclaringType+().getEnclosingFunction() = a.getEnclosingFunction()
33+
) and
34+
exists(PointerOrArrayType type |
35+
// include only pointers which point to a const-qualified type
36+
this.getType() = type and
37+
not type.isDeeplyConstBelow()
38+
) and
39+
// exclude pointers passed as arguments to functions which take a
40+
// parameter that points to a non-const-qualified type
41+
not exists(FunctionCall fc, int i |
42+
fc.getArgument(i) = this.getAnAccess() and
43+
not fc.getTarget().getParameter(i).getType().isDeeplyConstBelow()
44+
) and
45+
// exclude any pointers which have their underlying data modified
46+
not exists(VariableEffect effect |
47+
effect.getTarget() = this and
48+
// but not pointers that are only themselves modified
49+
not effect.(AssignExpr).getLValue() = this.getAnAccess() and
50+
not effect.(CrementOperation).getOperand() = this.getAnAccess()
51+
) and
52+
// exclude pointers assigned to another pointer to a non-const-qualified type
53+
not exists(Variable a |
54+
a.getAnAssignedValue() = this.getAnAccess() and
55+
not a.getType().(PointerOrArrayType).isDeeplyConstBelow()
56+
)
57+
}
58+
}
59+
60+
/**
61+
* Ensure that all copies of a variable are considered to be missing const qualification to avoid
62+
* false positives where a variable is only used/modified in a single copy.
63+
*/
64+
class NonConstPointerVariable =
65+
HoldsForAllCopies<NonConstPointerVariableCandidate, Variable>::LogicalResultElement;
66+
67+
from NonConstPointerVariable ptr
2368
where
24-
not isExcluded(ptr, Pointers1Package::pointerShouldPointToConstTypeWhenPossibleQuery()) and
25-
// include only pointers which point to a const-qualified type
26-
ptr.getType() = type and
27-
not type.isDeeplyConstBelow() and
28-
// exclude pointers passed as arguments to functions which take a
29-
// parameter that points to a non-const-qualified type
30-
not exists(FunctionCall fc, int i |
31-
fc.getArgument(i) = ptr.getAnAccess() and
32-
not fc.getTarget().getParameter(i).getType().isDeeplyConstBelow()
33-
) and
34-
// exclude any pointers which have their underlying data modified
35-
not exists(VariableEffect effect |
36-
effect.getTarget() = ptr and
37-
// but not pointers that are only themselves modified
38-
not effect.(AssignExpr).getLValue() = effect.getAnAccess() and
39-
not effect.(CrementOperation).getOperand() = effect.getAnAccess()
40-
) and
41-
// exclude pointers assigned to another pointer to a non-const-qualified type
42-
not exists(Variable a |
43-
a.getAnAssignedValue() = ptr.getAnAccess() and
44-
not a.getType().(PointerOrArrayType).isDeeplyConstBelow()
45-
)
46-
select ptr, "$@ points to a non-const-qualified type.", ptr, ptr.getName()
69+
not isExcluded(ptr.getAnElementInstance(),
70+
Pointers1Package::pointerShouldPointToConstTypeWhenPossibleQuery())
71+
select ptr, "$@ points to a non-const-qualified type.", ptr, ptr.getAnElementInstance().getName()
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
| test.c:8:6:8:35 | ____codeql_coding_standards_m2 | May result in undefined behavior. |
2-
| test.c:11:5:11:34 | ____codeql_coding_standards_m3 | May result in undefined behavior. |
3-
| test.c:15:5:15:34 | ____codeql_coding_standards_m4 | May result in undefined behavior. |
4-
| test.c:19:5:19:34 | ____codeql_coding_standards_m5 | May result in undefined behavior. |
5-
| test.c:23:5:23:34 | ____codeql_coding_standards_m6 | May result in undefined behavior. |
1+
| test.c:4:6:4:38 | ____codeql_coding_standards_main1 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |
2+
| test.c:8:5:8:37 | ____codeql_coding_standards_main2 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |
3+
| test.c:27:5:27:37 | ____codeql_coding_standards_main6 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |
4+
| test.c:32:6:32:38 | ____codeql_coding_standards_main7 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |
5+
| test.c:36:5:36:37 | ____codeql_coding_standards_main8 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |
6+
| test.c:40:5:40:37 | ____codeql_coding_standards_main9 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |
7+
| test.c:44:5:44:38 | ____codeql_coding_standards_main10 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |
8+
| test.c:48:5:48:38 | ____codeql_coding_standards_main11 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. |

c/misra/test/rules/RULE-1-3/test.c

+32-7
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,50 @@
1-
void main(void) { // COMPLIANT
1+
int main(void) { // COMPLIANT
22
}
33

4-
int ____codeql_coding_standards_m1(int argc, char **argv) { // NON_COMPLIANT
4+
void ____codeql_coding_standards_main1(void) { // NON_COMPLIANT
55
return 0;
66
}
77

8-
void ____codeql_coding_standards_m2(char *argc, char **argv) { // NON_COMPLIANT
8+
int ____codeql_coding_standards_main2() { // NON_COMPLIANT
9+
return 0;
10+
}
11+
12+
int ____codeql_coding_standards_main3(int argc, char **argv) { // COMPLIANT
13+
return 0;
14+
}
15+
16+
int ____codeql_coding_standards_main4(int argc, char argv[][]) { // COMPLIANT
17+
return 0;
18+
}
19+
20+
int ____codeql_coding_standards_main5(int argc, char *argv[]) { // COMPLIANT
21+
return 0;
22+
}
23+
24+
typedef int MY_INT;
25+
typedef char *MY_CHAR_PTR;
26+
27+
int ____codeql_coding_standards_main6(MY_INT argc,
28+
MY_CHAR_PTR argv[]) { // COMPLIANT
29+
return 0;
30+
}
31+
32+
void ____codeql_coding_standards_main7(char *argc,
33+
char **argv) { // NON_COMPLIANT
934
}
1035

11-
int ____codeql_coding_standards_m3(int argc, char *argv) { // NON_COMPLIANT
36+
int ____codeql_coding_standards_main8(int argc, char *argv) { // NON_COMPLIANT
1237
return 0;
1338
}
1439

15-
int ____codeql_coding_standards_m4() { // NON_COMPLIANT
40+
int ____codeql_coding_standards_main9() { // NON_COMPLIANT
1641
return 0;
1742
}
1843

19-
int ____codeql_coding_standards_m5(int argc, int *argv) { // NON_COMPLIANT
44+
int ____codeql_coding_standards_main10(int argc, int *argv) { // NON_COMPLIANT
2045
return 0;
2146
}
2247

23-
int ____codeql_coding_standards_m6(int argc, int **argv) { // NON_COMPLIANT
48+
int ____codeql_coding_standards_main11(int argc, int **argv) { // NON_COMPLIANT
2449
return 0;
2550
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
| header3.h:7:1:7:24 | #define MULTIPLE_INCLUDE | Definition of macro MULTIPLE_INCLUDE is not distinct from alternative definition of $@ in rules/RULE-5-4/header4.h. | header4.h:1:1:1:24 | #define MULTIPLE_INCLUDE | MULTIPLE_INCLUDE |
2+
| header3.h:14:1:14:21 | #define NOT_PROTECTED | Definition of macro NOT_PROTECTED is not distinct from alternative definition of $@ in rules/RULE-5-4/header4.h. | header4.h:12:1:12:23 | #define NOT_PROTECTED 1 | NOT_PROTECTED |
13
| test.c:2:1:2:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB | Macro identifer iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB is nondistinct in first 63 characters, compared to $@. | test.c:1:1:1:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA | iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA |
2-
| test.c:8:1:8:31 | #define FUNCTION_MACRO(X) X + 1 | Macro identifer FUNCTION_MACRO is nondistinct in first 63 characters, compared to $@. | test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | FUNCTION_MACRO |
4+
| test.c:8:1:8:31 | #define FUNCTION_MACRO(X) X + 1 | Definition of macro FUNCTION_MACRO is not distinct from alternative definition of $@ in rules/RULE-5-4/test.c. | test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | FUNCTION_MACRO |
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifdef FOO
2+
#include "header1.h"
3+
#else
4+
#include "header2.h"
5+
#endif
6+
7+
#ifdef FOO
8+
#define A_MACRO 1 // COMPLIANT
9+
#else
10+
#define A_MACRO 2 // COMPLIANT
11+
#endif

c/misra/test/rules/RULE-5-4/header1.h

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#define REPEATED 11 // COMPLIANT

c/misra/test/rules/RULE-5-4/header2.h

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#define REPEATED 1 // COMPLIANT

c/misra/test/rules/RULE-5-4/header3.h

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef HEADER3_H
2+
#define HEADER3_H
3+
4+
// We should ignore the header guards in this file
5+
6+
// This is defined unconditionally by both header3.h and header4.h
7+
#define MULTIPLE_INCLUDE // NON_COMPLIANT
8+
9+
// This is redefined in header3.h, but only if it isn't already defined
10+
#define PROTECTED // COMPLIANT
11+
12+
// This is redefined in header3.h, but is conditional on some other condition,
13+
// so this is redefined
14+
#define NOT_PROTECTED // NON_COMPLIANT
15+
16+
#endif

c/misra/test/rules/RULE-5-4/header4.h

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#define MULTIPLE_INCLUDE // NON_COMPLIANT
2+
3+
// This case is triggered from root2.c
4+
// because PROTECTED isn't defined in
5+
// that case
6+
#ifndef PROTECTED
7+
#define PROTECTED // COMPLIANT - checked by guard
8+
#endif
9+
10+
// Always enabled, so conflicts in root1.c case
11+
#ifdef MULTIPLE_INCLUDE
12+
#define NOT_PROTECTED 1 // NON_COMPLIANT
13+
#endif

c/misra/test/rules/RULE-5-4/root1.c

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#define FOO 1
2+
#include "conditional.h"
3+
4+
// Both headers define MULTIPLE_INCLUDE
5+
#include "header3.h"
6+
#include "header4.h"

c/misra/test/rules/RULE-5-4/root2.c

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "conditional.h"
2+
3+
#include "header4.h"

c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
| test.c:66:23:66:24 | p1 | $@ points to a non-const-qualified type. | test.c:66:23:66:24 | p1 | p1 |
1313
| test.c:71:17:71:18 | p1 | $@ points to a non-const-qualified type. | test.c:71:17:71:18 | p1 | p1 |
1414
| test.c:75:15:75:16 | p1 | $@ points to a non-const-qualified type. | test.c:75:15:75:16 | p1 | p1 |
15+
| test.c:103:30:103:30 | s | $@ points to a non-const-qualified type. | test.c:103:30:103:30 | s | s |

0 commit comments

Comments
 (0)