Skip to content

Commit b752a6c

Browse files
authored
Merge pull request #2381 from jbj/StackVariable
C++: Add StackVariable class, preferred over LocalScopeVariable
2 parents cfcd18b + 763b18c commit b752a6c

File tree

62 files changed

+350
-346
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+350
-346
lines changed

change-notes/1.24/analysis-cpp.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,11 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
1717

1818
## Changes to libraries
1919

20-
*
20+
* The new class `StackVariable` should be used in place of `LocalScopeVariable`
21+
in most cases. The difference is that `StackVariable` does not include
22+
variables declared with `static` or `thread_local`.
23+
* As a rule of thumb, custom queries about the _values_ of variables should
24+
be changed from `LocalScopeVariable` to `StackVariable`, while queries
25+
about the _name or scope_ of variables should remain unchanged.
26+
* The `LocalScopeVariableReachability` library is deprecated in favor of
27+
`StackVariableReachability`. The functionality is the same.

cpp/ql/src/Critical/DeadCodeCondition.ql

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ predicate testAndBranch(Expr e, Stmt branch) {
2222
)
2323
}
2424

25-
predicate choice(LocalScopeVariable v, Stmt branch, string value) {
25+
predicate choice(StackVariable v, Stmt branch, string value) {
2626
exists(AnalysedExpr e |
2727
testAndBranch(e, branch) and
2828
(
@@ -33,7 +33,7 @@ predicate choice(LocalScopeVariable v, Stmt branch, string value) {
3333
)
3434
}
3535

36-
predicate guarded(LocalScopeVariable v, Stmt loopstart, AnalysedExpr child) {
36+
predicate guarded(StackVariable v, Stmt loopstart, AnalysedExpr child) {
3737
choice(v, loopstart, _) and
3838
loopstart.getChildStmt*() = child.getEnclosingStmt() and
3939
(definition(v, child) or exists(child.getNullSuccessor(v)))
@@ -47,9 +47,7 @@ predicate addressLeak(Variable v, Stmt leak) {
4747
)
4848
}
4949

50-
from
51-
LocalScopeVariable v, Stmt branch, AnalysedExpr cond, string context, string test,
52-
string testresult
50+
from StackVariable v, Stmt branch, AnalysedExpr cond, string context, string test, string testresult
5351
where
5452
choice(v, branch, context) and
5553
forall(ControlFlowNode def | definition(v, def) and definitionReaches(def, cond) |

cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ predicate closeCall(FunctionCall fc, Variable v) {
2323
)
2424
}
2525

26-
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) {
26+
predicate openDefinition(StackVariable v, ControlFlowNode def) {
2727
exists(Expr expr | exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
2828
}
2929

3030
predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
31-
exists(LocalScopeVariable v | openDefinition(v, def) and node = def.getASuccessor())
31+
exists(StackVariable v | openDefinition(v, def) and node = def.getASuccessor())
3232
or
33-
exists(LocalScopeVariable v, ControlFlowNode mid |
33+
exists(StackVariable v, ControlFlowNode mid |
3434
openDefinition(v, def) and
3535
openReaches(def, mid) and
3636
not errorSuccessor(v, mid) and
@@ -40,15 +40,15 @@ predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
4040
)
4141
}
4242

43-
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
43+
predicate assignedToFieldOrGlobal(StackVariable v, Assignment assign) {
4444
exists(Variable external |
4545
assign.getRValue() = v.getAnAccess() and
4646
assign.getLValue().(VariableAccess).getTarget() = external and
4747
(external instanceof Field or external instanceof GlobalVariable)
4848
)
4949
}
5050

51-
from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret
51+
from StackVariable v, ControlFlowNode def, ReturnStmt ret
5252
where
5353
openDefinition(v, def) and
5454
openReaches(def, ret) and

cpp/ql/src/Critical/FileMayNotBeClosed.ql

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*/
1111

1212
import FileClosed
13-
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
13+
import semmle.code.cpp.controlflow.StackVariableReachability
1414

1515
/**
1616
* Extend the NullValue class used by Nullness.qll to include simple -1 as a 'null' value
@@ -68,18 +68,18 @@ predicate fcloseCallOrIndirect(FunctionCall fc, Variable v) {
6868
)
6969
}
7070

71-
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) {
71+
predicate fopenDefinition(StackVariable v, ControlFlowNode def) {
7272
exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr))
7373
}
7474

75-
class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
75+
class FOpenVariableReachability extends StackVariableReachabilityWithReassignment {
7676
FOpenVariableReachability() { this = "FOpenVariableReachability" }
7777

78-
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
78+
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
7979
fopenDefinition(v, node)
8080
}
8181

82-
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
82+
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
8383
// node may be used in fopenReaches
8484
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
8585
fcloseCallOrIndirect(node, v) or
@@ -88,15 +88,13 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
8888
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
8989
}
9090

91-
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
92-
definitionBarrier(v, node)
93-
}
91+
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
9492
}
9593

9694
/**
9795
* The value from fopen at `def` is still held in Variable `v` upon entering `node`.
9896
*/
99-
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
97+
predicate fopenVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
10098
exists(FOpenVariableReachability r |
10199
// reachability
102100
r.reachesTo(def, _, node, v)
@@ -107,25 +105,23 @@ predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, Contro
107105
)
108106
}
109107

110-
class FOpenReachability extends LocalScopeVariableReachabilityExt {
108+
class FOpenReachability extends StackVariableReachabilityExt {
111109
FOpenReachability() { this = "FOpenReachability" }
112110

113-
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
114-
fopenDefinition(v, node)
115-
}
111+
override predicate isSource(ControlFlowNode node, StackVariable v) { fopenDefinition(v, node) }
116112

117-
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
113+
override predicate isSink(ControlFlowNode node, StackVariable v) {
118114
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
119115
}
120116

121117
override predicate isBarrier(
122-
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
118+
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
123119
) {
124120
isSource(source, v) and
125121
next = node.getASuccessor() and
126122
// the file (stored in any variable `v0`) opened at `source` is closed or
127123
// assigned to a global at node, or NULL checked on the edge node -> next.
128-
exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) |
124+
exists(StackVariable v0 | fopenVariableReaches(v0, source, node) |
129125
node.(AnalysedExpr).getNullSuccessor(v0) = next or
130126
fcloseCallOrIndirect(node, v0) or
131127
assignedToFieldOrGlobal(v0, node)
@@ -142,11 +138,11 @@ predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) {
142138
exists(FOpenReachability r | r.reaches(def, _, node))
143139
}
144140

145-
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
146-
// assigned to anything except a LocalScopeVariable
141+
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
142+
// assigned to anything except a StackVariable
147143
// (typically a field or global, but for example also *ptr = v)
148144
e.(Assignment).getRValue() = v.getAnAccess() and
149-
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
145+
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
150146
or
151147
exists(Expr midExpr, Function mid, int arg |
152148
// indirect assignment
@@ -163,7 +159,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
163159
from ControlFlowNode def, ReturnStmt ret
164160
where
165161
fopenReaches(def, ret) and
166-
not exists(LocalScopeVariable v |
162+
not exists(StackVariable v |
167163
fopenVariableReaches(v, def, ret) and
168164
ret.getAChild*() = v.getAnAccess()
169165
)

cpp/ql/src/Critical/InconsistentNullnessTesting.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import cpp
1313

14-
from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
14+
from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
1515
where
1616
checked = v.getAnAccess() and
1717
dereferenced(checked) and

cpp/ql/src/Critical/LateNegativeTest.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import cpp
1515

16-
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
16+
predicate negativeCheck(StackVariable v, ComparisonOperation op) {
1717
exists(int varindex, string constant, Literal lit |
1818
op.getChild(varindex) = v.getAnAccess() and
1919
op.getChild(1 - varindex) = lit and
@@ -38,7 +38,7 @@ predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
3838
)
3939
}
4040

41-
from LocalScopeVariable v, ArrayExpr dangerous, Expr check
41+
from StackVariable v, ArrayExpr dangerous, Expr check
4242
where
4343
useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and
4444
negativeCheck(v, check) and

cpp/ql/src/Critical/MemoryMayNotBeFreed.ql

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*/
1111

1212
import MemoryFreed
13-
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
13+
import semmle.code.cpp.controlflow.StackVariableReachability
1414

1515
/**
1616
* 'call' is either a direct call to f, or a possible call to f
@@ -97,18 +97,18 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
9797
)
9898
}
9999

100-
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) {
100+
predicate allocationDefinition(StackVariable v, ControlFlowNode def) {
101101
exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr))
102102
}
103103

104-
class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
104+
class AllocVariableReachability extends StackVariableReachabilityWithReassignment {
105105
AllocVariableReachability() { this = "AllocVariableReachability" }
106106

107-
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
107+
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
108108
allocationDefinition(v, node)
109109
}
110110

111-
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
111+
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
112112
// node may be used in allocationReaches
113113
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
114114
freeCallOrIndirect(node, v) or
@@ -117,15 +117,13 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
117117
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
118118
}
119119

120-
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
121-
definitionBarrier(v, node)
122-
}
120+
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
123121
}
124122

125123
/**
126124
* The value from allocation `def` is still held in Variable `v` upon entering `node`.
127125
*/
128-
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
126+
predicate allocatedVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
129127
exists(AllocVariableReachability r |
130128
// reachability
131129
r.reachesTo(def, _, node, v)
@@ -136,25 +134,25 @@ predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, Co
136134
)
137135
}
138136

139-
class AllocReachability extends LocalScopeVariableReachabilityExt {
137+
class AllocReachability extends StackVariableReachabilityExt {
140138
AllocReachability() { this = "AllocReachability" }
141139

142-
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
140+
override predicate isSource(ControlFlowNode node, StackVariable v) {
143141
allocationDefinition(v, node)
144142
}
145143

146-
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
144+
override predicate isSink(ControlFlowNode node, StackVariable v) {
147145
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
148146
}
149147

150148
override predicate isBarrier(
151-
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
149+
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
152150
) {
153151
isSource(source, v) and
154152
next = node.getASuccessor() and
155153
// the memory (stored in any variable `v0`) allocated at `source` is freed or
156154
// assigned to a global at node, or NULL checked on the edge node -> next.
157-
exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) |
155+
exists(StackVariable v0 | allocatedVariableReaches(v0, source, node) |
158156
node.(AnalysedExpr).getNullSuccessor(v0) = next or
159157
freeCallOrIndirect(node, v0) or
160158
assignedToFieldOrGlobal(v0, node)
@@ -171,11 +169,11 @@ predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) {
171169
exists(AllocReachability r | r.reaches(def, _, node))
172170
}
173171

174-
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
175-
// assigned to anything except a LocalScopeVariable
172+
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
173+
// assigned to anything except a StackVariable
176174
// (typically a field or global, but for example also *ptr = v)
177175
e.(Assignment).getRValue() = v.getAnAccess() and
178-
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
176+
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
179177
or
180178
exists(Expr midExpr, Function mid, int arg |
181179
// indirect assignment
@@ -192,7 +190,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
192190
from ControlFlowNode def, ReturnStmt ret
193191
where
194192
allocationReaches(def, ret) and
195-
not exists(LocalScopeVariable v |
193+
not exists(StackVariable v |
196194
allocatedVariableReaches(v, def, ret) and
197195
ret.getAChild*() = v.getAnAccess()
198196
)

cpp/ql/src/Critical/MissingNegativityTest.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class FunctionWithNegativeReturn extends Function {
4343
predicate dangerousUse(IntegralReturnValue val, Expr use) {
4444
exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val)
4545
or
46-
exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae |
46+
exists(StackVariable v, ControlFlowNode def, ArrayExpr ae |
4747
exprDefinition(v, def, val) and
4848
use = ae.getArrayOffset() and
4949
not boundsChecked(v, use) and
@@ -54,7 +54,7 @@ predicate dangerousUse(IntegralReturnValue val, Expr use) {
5454
val = use and
5555
use.getType().getUnderlyingType() instanceof PointerType
5656
or
57-
exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add |
57+
exists(StackVariable v, ControlFlowNode def, AddExpr add |
5858
exprDefinition(v, def, val) and
5959
definitionUsePair(v, def, use) and
6060
add.getAnOperand() = use and

cpp/ql/src/Critical/NewDelete.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
6060
pragma[nomagic]
6161
private predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
6262
exists(Expr mid |
63-
not v instanceof LocalScopeVariable and
63+
not v instanceof StackVariable and
6464
v.getAnAssignedValue() = mid and
6565
allocReaches0(mid, alloc, kind)
6666
)
@@ -76,7 +76,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) {
7676
allocExprOrIndirect(alloc, kind) and
7777
e = alloc
7878
or
79-
exists(SsaDefinition def, LocalScopeVariable v |
79+
exists(SsaDefinition def, StackVariable v |
8080
// alloc via SSA
8181
allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and
8282
e = def.getAUse(v)

cpp/ql/src/Critical/OverflowCalculated.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class MallocCall extends FunctionCall {
1818
Expr getAllocatedSize() {
1919
if this.getArgument(0) instanceof VariableAccess
2020
then
21-
exists(LocalScopeVariable v, ControlFlowNode def |
21+
exists(StackVariable v, ControlFlowNode def |
2222
definitionUsePair(v, def, this.getArgument(0)) and
2323
exprDefinition(v, def, result)
2424
)

0 commit comments

Comments
 (0)