Skip to content

Commit 436a9ce

Browse files
authored
Merge pull request #15460 from MathiasVP/fix-scanf-fp-2
C++: Fix another FP in `cpp/incorrectly-checked-scanf`
2 parents aeae208 + 5024df9 commit 436a9ce

File tree

4 files changed

+35
-7
lines changed

4 files changed

+35
-7
lines changed

cpp/ql/src/Critical/ScanfChecks.qll

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ private import semmle.code.cpp.commons.Scanf
33
private import semmle.code.cpp.controlflow.IRGuards
44
private import semmle.code.cpp.ir.ValueNumbering
55

6+
private ConstantInstruction getZeroInstruction() { result.getValue() = "0" }
7+
8+
private Operand zero() { result.getDef() = getZeroInstruction() }
9+
610
private predicate exprInBooleanContext(Expr e) {
711
exists(IRGuardCondition gc |
8-
exists(Instruction i, ConstantInstruction zero |
9-
zero.getValue() = "0" and
12+
exists(Instruction i |
1013
i.getUnconvertedResultExpression() = e and
11-
gc.comparesEq(valueNumber(i).getAUse(), zero.getAUse(), 0, _, _)
14+
gc.comparesEq(valueNumber(i).getAUse(), zero(), 0, _, _)
1215
)
1316
or
1417
gc.getUnconvertedResultExpression() = e
@@ -33,15 +36,21 @@ private string getEofValue() {
3336
)
3437
}
3538

39+
private ConstantInstruction getEofInstruction() { result.getValue() = getEofValue() }
40+
41+
private Operand eof() { result.getDef() = getEofInstruction() }
42+
3643
/**
3744
* Holds if the value of `call` has been checked to not equal `EOF`.
3845
*/
3946
private predicate checkedForEof(ScanfFunctionCall call) {
4047
exists(IRGuardCondition gc |
41-
exists(Instruction i, ConstantInstruction eof |
42-
eof.getValue() = getEofValue() and
43-
i.getUnconvertedResultExpression() = call and
44-
gc.comparesEq(valueNumber(i).getAUse(), eof.getAUse(), 0, _, _)
48+
exists(Instruction i | i.getUnconvertedResultExpression() = call |
49+
// call == EOF
50+
gc.comparesEq(valueNumber(i).getAUse(), eof(), 0, _, _)
51+
or
52+
// call < 0 (EOF is guaranteed to be negative)
53+
gc.comparesLt(valueNumber(i).getAUse(), zero(), 0, true, _)
4554
)
4655
)
4756
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The "Incorrect return-value check for a 'scanf'-like function" query (`cpp/incorrectly-checked-scanf`) now recognizes more EOF checks.

cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
1616
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
1717
| test.cpp:460:6:460:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:455:12:455:17 | call to sscanf | call to sscanf |
18+
| test.cpp:474:6:474:10 | value | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:467:8:467:12 | call to scanf | call to scanf |

cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,4 +458,18 @@ void disjunct_boolean_condition(const char* modifier_data) {
458458
return;
459459
}
460460
use(value); // GOOD
461+
}
462+
463+
void check_for_negative_test() {
464+
int res;
465+
int value;
466+
467+
res = scanf("%d", &value); // GOOD
468+
if(res == 0) {
469+
return;
470+
}
471+
if (res < 0) {
472+
return;
473+
}
474+
use(value);
461475
}

0 commit comments

Comments
 (0)