Skip to content

Commit 8b536f5

Browse files
authored
Merge pull request #17481 from github/calumgrant/bmn/uninitialized-local
C++: Remove FPs from cpp/uninitialized-local when encountered extraction errors
2 parents 5fb61b0 + d3695dc commit 8b536f5

File tree

9 files changed

+37
-4
lines changed

9 files changed

+37
-4
lines changed

cpp/ql/lib/semmle/code/cpp/Function.qll

+11
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,17 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
500500
* Gets the nearest enclosing AccessHolder.
501501
*/
502502
override AccessHolder getEnclosingAccessHolder() { result = this.getDeclaringType() }
503+
504+
/**
505+
* Holds if this function has extraction errors that create an `ErrorExpr`.
506+
*/
507+
predicate hasErrors() {
508+
exists(ErrorExpr e |
509+
e.getEnclosingFunction() = this and
510+
// Exclude the first allocator call argument because it is always extracted as `ErrorExpr`.
511+
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
512+
)
513+
}
503514
}
504515

505516
pragma[noinline]

cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ where
5757
not declarationHasSideEffects(v) and
5858
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
5959
not v.getAnAttribute().getName() = "unused" and
60-
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
60+
not f.hasErrors() // Unextracted expressions may use `v`
6161
select v, "Variable " + v.getName() + " is not used."

cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
2929
override predicate isSource(Instruction source) {
3030
exists(Function func |
3131
// Rule out FPs caused by extraction errors.
32-
not any(ErrorExpr e).getEnclosingFunction() = func and
32+
not func.hasErrors() and
3333
not intentionallyReturnsStackPointer(func) and
3434
func = source.getEnclosingFunction()
3535
|

cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) {
6565
exists(LoadInstruction load |
6666
va = load.getUnconvertedResultExpression() and
6767
not va = commonException() and
68+
not va.getTarget().(LocalVariable).getFunction().hasErrors() and
6869
sink = load.getSourceValue()
6970
)
7071
}

cpp/ql/src/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ predicate instructionHasVariable(VariableAddressInstruction vai, StackVariable v
2424
// Pointer-to-member types aren't properly handled in the dbscheme.
2525
not vai.getResultType() instanceof PointerToMemberType and
2626
// Rule out FPs caused by extraction errors.
27-
not any(ErrorExpr e).getEnclosingFunction() = f
27+
not f.hasErrors()
2828
}
2929

3030
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.

cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
4949
predicate functionImperfectlyExtracted(Function f) {
5050
exists(CompilerError e | f.getBlock().getLocation().subsumes(e.getLocation()))
5151
or
52-
exists(ErrorExpr ee | ee.getEnclosingFunction() = f)
52+
f.hasErrors()
5353
or
5454
count(f.getType()) > 1
5555
or

cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/tests/UninitializedLocal.expected

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
edges
22
nodes
3+
| errors.cpp:13:7:13:7 | definition of x | semmle.label | definition of x |
34
| test.cpp:11:6:11:8 | definition of foo | semmle.label | definition of foo |
45
| test.cpp:111:6:111:8 | definition of foo | semmle.label | definition of foo |
56
| test.cpp:226:7:226:7 | definition of x | semmle.label | definition of x |
@@ -14,6 +15,7 @@ nodes
1415
| test.cpp:472:6:472:6 | definition of x | semmle.label | definition of x |
1516
| test.cpp:479:6:479:6 | definition of x | semmle.label | definition of x |
1617
#select
18+
| errors.cpp:14:18:14:18 | x | errors.cpp:13:7:13:7 | definition of x | errors.cpp:13:7:13:7 | definition of x | The variable $@ may not be initialized at this access. | errors.cpp:13:7:13:7 | x | x |
1719
| test.cpp:12:6:12:8 | foo | test.cpp:11:6:11:8 | definition of foo | test.cpp:11:6:11:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
1820
| test.cpp:113:6:113:8 | foo | test.cpp:111:6:111:8 | definition of foo | test.cpp:111:6:111:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
1921
| test.cpp:227:3:227:3 | x | test.cpp:226:7:226:7 | definition of x | test.cpp:226:7:226:7 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:226:7:226:7 | x | x |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// semmle-extractor-options: --expect_errors
2+
3+
int f1() {
4+
int x;
5+
initialize(&x); // error expression - initialize() is not defined
6+
return x; // GOOD - assume x is initialized
7+
}
8+
9+
void * operator new(unsigned long, bool);
10+
void operator delete(void*, bool);
11+
12+
int f2() {
13+
int x;
14+
new(true) int (x); // BAD, ignore implicit error expression
15+
}

0 commit comments

Comments
 (0)