Skip to content

Commit 669ac2f

Browse files
C++: Fix FP in PointlessComparison due to preprocessor
Reported by an LGTM customer here: https://discuss.lgtm.com/t/2-false-positives-in-c-for-comparison-is-always-same/1943. Even though the comparison is pointless in the preprocessor configuration in effect during extraction, it is not pointless in other preprocessor configurations. Similar to ExprHasNoEffect, we'll now exclude results in functions that contain preprocessor-excluded code. I factored the similar code already used in ExprHasNoEffect in a non-recursive version into Preprocessor.qll, leaving the recursive version in ExprHasNoEffect.ql. I believe the recursive version is too aggressive for PointerlessComparison, which does no interprocedural analysis.
1 parent 1be9762 commit 669ac2f

File tree

4 files changed

+82
-48
lines changed

4 files changed

+82
-48
lines changed

cpp/ql/src/Likely Bugs/Arithmetic/PointlessComparison.ql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ from
3131
where
3232
not cmp.isInMacroExpansion() and
3333
not cmp.isFromTemplateInstantiation(_) and
34+
not containsDisabledCode(cmp.getEnclosingFunction()) and
3435
reachablePointlessComparison(cmp, left, right, value, ss) and
3536

3637
// a comparison between an enum and zero is always valid because whether

cpp/ql/src/Likely Bugs/Likely Typos/ExprHasNoEffect.ql

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,67 +23,25 @@ predicate accessInInitOfForStmt(Expr e) {
2323
s.getExpr() = e)
2424
}
2525

26-
/**
27-
* Holds if the preprocessor branch `pbd` is on line `pbdStartLine` in file `file`.
28-
*/
29-
predicate pbdLocation(PreprocessorBranchDirective pbd, string file, int pbdStartLine) {
30-
pbd.getLocation().hasLocationInfo(file, pbdStartLine, _, _, _)
31-
}
32-
33-
/**
34-
* Holds if the body of the function `f` is on lines `fBlockStartLine` to `fBlockEndLine` in file `file`.
35-
*/
36-
predicate functionLocation(Function f, string file, int fBlockStartLine, int fBlockEndLine) {
37-
f.getBlock().getLocation().hasLocationInfo(file, fBlockStartLine, _, fBlockEndLine, _)
38-
}
3926
/**
4027
* Holds if the function `f`, or a function called by it, contains
4128
* code excluded by the preprocessor.
4229
*/
43-
predicate containsDisabledCode(Function f) {
44-
// `f` contains a preprocessor branch that was not taken
45-
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int fBlockStartLine, int fBlockEndLine |
46-
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
47-
pbdLocation(pbd, file, pbdStartLine) and
48-
pbdStartLine <= fBlockEndLine and
49-
pbdStartLine >= fBlockStartLine and
50-
(
51-
pbd.(PreprocessorBranch).wasNotTaken() or
52-
53-
// an else either was not taken, or it's corresponding branch
54-
// was not taken.
55-
pbd instanceof PreprocessorElse
56-
)
57-
) or
58-
30+
predicate containsDisabledCodeRecursive(Function f) {
31+
containsDisabledCode(f) or
5932
// recurse into function calls
6033
exists(FunctionCall fc |
6134
fc.getEnclosingFunction() = f and
6235
containsDisabledCode(fc.getTarget())
6336
)
6437
}
6538

66-
6739
/**
6840
* Holds if the function `f`, or a function called by it, is inside a
6941
* preprocessor branch that may have code in another arm
7042
*/
71-
predicate definedInIfDef(Function f) {
72-
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int pbdEndLine, int fBlockStartLine, int fBlockEndLine |
73-
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
74-
pbdLocation(pbd, file, pbdStartLine) and
75-
pbdLocation(pbd.getNext(), file, pbdEndLine) and
76-
pbdStartLine <= fBlockStartLine and
77-
pbdEndLine >= fBlockEndLine and
78-
// pbd is a preprocessor branch where multiple branches exist
79-
(
80-
pbd.getNext() instanceof PreprocessorElse or
81-
pbd instanceof PreprocessorElse or
82-
pbd.getNext() instanceof PreprocessorElif or
83-
pbd instanceof PreprocessorElif
84-
)
85-
) or
86-
43+
predicate definedInIfDefRecursive(Function f) {
44+
definedInIfDef(f) or
8745
// recurse into function calls
8846
exists(FunctionCall fc |
8947
fc.getEnclosingFunction() = f and
@@ -121,8 +79,8 @@ where // EQExprs are covered by CompareWhereAssignMeant.ql
12179
not parent instanceof PureExprInVoidContext and
12280
not peivc.getEnclosingFunction().isCompilerGenerated() and
12381
not peivc.getType() instanceof UnknownType and
124-
not containsDisabledCode(peivc.(FunctionCall).getTarget()) and
125-
not definedInIfDef(peivc.(FunctionCall).getTarget()) and
82+
not containsDisabledCodeRecursive(peivc.(FunctionCall).getTarget()) and
83+
not definedInIfDefRecursive(peivc.(FunctionCall).getTarget()) and
12684
if peivc instanceof FunctionCall then
12785
exists(Function target |
12886
target = peivc.(FunctionCall).getTarget() and

cpp/ql/src/semmle/code/cpp/Preprocessor.qll

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,64 @@ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma {
221221
class PreprocessorLine extends PreprocessorDirective, @ppd_line {
222222
override string toString() { result = "#line " + this.getHead() }
223223
}
224+
225+
/**
226+
* Holds if the preprocessor branch `pbd` is on line `pbdStartLine` in file `file`.
227+
*/
228+
private predicate pbdLocation(PreprocessorBranchDirective pbd, string file, int pbdStartLine) {
229+
pbd.getLocation().hasLocationInfo(file, pbdStartLine, _, _, _)
230+
}
231+
232+
/**
233+
* Holds if the body of the function `f` is on lines `fBlockStartLine` to `fBlockEndLine` in file `file`.
234+
*/
235+
private predicate functionLocation(Function f, string file, int fBlockStartLine, int fBlockEndLine) {
236+
f.getBlock().getLocation().hasLocationInfo(file, fBlockStartLine, _, fBlockEndLine, _)
237+
}
238+
239+
/**
240+
* Holds if the function `f` is inside a preprocessor branch that may have code in another arm.
241+
*/
242+
predicate definedInIfDef(Function f) {
243+
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int pbdEndLine, int fBlockStartLine,
244+
int fBlockEndLine |
245+
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
246+
pbdLocation(pbd, file, pbdStartLine) and
247+
pbdLocation(pbd.getNext(), file, pbdEndLine) and
248+
pbdStartLine <= fBlockStartLine and
249+
pbdEndLine >= fBlockEndLine and
250+
// pbd is a preprocessor branch where multiple branches exist
251+
(
252+
pbd.getNext() instanceof PreprocessorElse or
253+
pbd instanceof PreprocessorElse or
254+
pbd.getNext() instanceof PreprocessorElif or
255+
pbd instanceof PreprocessorElif
256+
)
257+
)
258+
}
259+
260+
/**
261+
* Holds if the function `f`, or a function called by it, contains
262+
* code excluded by the preprocessor.
263+
*/
264+
predicate containsDisabledCode(Function f) {
265+
// `f` contains a preprocessor branch that was not taken
266+
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int fBlockStartLine, int fBlockEndLine |
267+
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
268+
pbdLocation(pbd, file, pbdStartLine) and
269+
pbdStartLine <= fBlockEndLine and
270+
pbdStartLine >= fBlockStartLine and
271+
(
272+
pbd.(PreprocessorBranch).wasNotTaken() or
273+
274+
// an else either was not taken, or it's corresponding branch
275+
// was not taken.
276+
pbd instanceof PreprocessorElse
277+
)
278+
) or
279+
// recurse into function calls
280+
exists(FunctionCall fc |
281+
fc.getEnclosingFunction() = f and
282+
containsDisabledCode(fc.getTarget())
283+
)
284+
}

cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/RegressionTests.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,17 @@ int regression_test_01(unsigned long bb) {
6666
return 1;
6767
}
6868
}
69+
70+
int containsIfDef(int x) {
71+
int result = 0;
72+
if (x > 0) {
73+
result = 1;
74+
}
75+
#if _CONDITION
76+
if (x < 0) {
77+
result = -1;
78+
}
79+
#endif
80+
81+
return result >= 0;
82+
}

0 commit comments

Comments
 (0)