Skip to content

Commit 237a7d3

Browse files
committed
C++: Exclusion rules for system macros
Unwanted results were reported for our JPL Rule 24 queries. Including system headers with complex macros could lead to unpredictable alerts from these rules.
1 parent b73a2f7 commit 237a7d3

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

cpp/ql/lib/semmle/code/cpp/commons/Exclusions.qll

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ predicate functionContainsPreprocCode(Function f) {
8181
}
8282

8383
/**
84-
* Holds if `e` is completely or partially from a macro definition, as opposed
85-
* to being passed in as an argument.
84+
* Holds if `e` is completely or partially from a macro invocation `mi`, as
85+
* opposed to being passed in as an argument.
8686
*
8787
* In the following example, the call to `f` is from a macro definition,
8888
* while `y`, `+`, `1`, and `;` are not. This assumes that no identifier apart
@@ -93,8 +93,8 @@ predicate functionContainsPreprocCode(Function f) {
9393
* M(y + 1);
9494
* ```
9595
*/
96-
predicate isFromMacroDefinition(Element e) {
97-
exists(MacroInvocation mi, Location eLocation, Location miLocation |
96+
private predicate isFromMacroInvocation(Element e, MacroInvocation mi) {
97+
exists(Location eLocation, Location miLocation |
9898
mi.getAnExpandedElement() = e and
9999
eLocation = e.getLocation() and
100100
miLocation = mi.getLocation() and
@@ -109,3 +109,39 @@ predicate isFromMacroDefinition(Element e) {
109109
eLocation.getEndColumn() >= miLocation.getEndColumn()
110110
)
111111
}
112+
113+
/**
114+
* Holds if `e` is completely or partially from a macro definition, as opposed
115+
* to being passed in as an argument.
116+
*
117+
* In the following example, the call to `f` is from a macro definition,
118+
* while `y`, `+`, `1`, and `;` are not. This assumes that no identifier apart
119+
* from `M` refers to a macro.
120+
* ```
121+
* #define M(x) f(x)
122+
* ...
123+
* M(y + 1);
124+
* ```
125+
*/
126+
predicate isFromMacroDefinition(Element e) {
127+
isFromMacroInvocation(e, _)
128+
}
129+
130+
/**
131+
* Holds if `e` is completely or partially from a _system macro_ definition, as
132+
* opposed to being passed in as an argument. A system macro is a macro whose
133+
* definition is outside the source directory of the database.
134+
*
135+
* If the system macro is invoked through a non-system macro, then this
136+
* predicate does not hold. That's a limitation of how macros are represented
137+
* in the database.
138+
*
139+
* See also `isFromMacroDefinition`.
140+
*/
141+
predicate isFromSystemMacroDefinition(Element e) {
142+
exists(MacroInvocation mi |
143+
isFromMacroInvocation(e, mi) and
144+
// Has no relative path in the database, meaning it's a system file.
145+
not exists(mi.getMacro().getFile().getRelativePath())
146+
)
147+
}

cpp/ql/src/JPL_C/LOC-4/Rule 24/MultipleStmtsPerLine.ql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111

1212
import cpp
13+
import semmle.code.cpp.commons.Exclusions
1314

1415
class OneLineStmt extends Stmt {
1516
OneLineStmt() {
@@ -34,5 +35,8 @@ where
3435
other.onLine(f, line) and toMin = other.getLocation().getStartColumn()
3536
|
3637
toMin
37-
)
38+
) and
39+
// Exclude statements that are from invocations of system-header macros.
40+
// Example: FD_ISSET from glibc.
41+
not isFromSystemMacroDefinition(o)
3842
select o, "This line contains " + cnt + " statements; only one is allowed."

cpp/ql/src/JPL_C/LOC-4/Rule 24/MultipleVarDeclsPerLine.ql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
1010
*/
1111

1212
import cpp
13+
import semmle.code.cpp.commons.Exclusions
1314

1415
from DeclStmt d
1516
where
1617
exists(Variable v1, Variable v2 | v1 = d.getADeclaration() and v2 = d.getADeclaration() |
1718
v1 != v2 and
1819
v1.getLocation().getStartLine() = v2.getLocation().getStartLine()
19-
)
20+
) and
21+
// Exclude declarations that are from invocations of system-header macros.
22+
// Example: FD_ZERO from glibc.
23+
not isFromSystemMacroDefinition(d)
2024
select d, "Multiple variable declarations on the same line."

0 commit comments

Comments
 (0)