mirror of
https://github.com/github/codeql.git
synced 2025-12-22 11:46:32 +01:00
Merge from master and resolve conflicts
This commit is contained in:
@@ -22,7 +22,7 @@ predicate testAndBranch(Expr e, Stmt branch) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate choice(LocalScopeVariable v, Stmt branch, string value) {
|
||||
predicate choice(StackVariable v, Stmt branch, string value) {
|
||||
exists(AnalysedExpr e |
|
||||
testAndBranch(e, branch) and
|
||||
(
|
||||
@@ -33,7 +33,7 @@ predicate choice(LocalScopeVariable v, Stmt branch, string value) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate guarded(LocalScopeVariable v, Stmt loopstart, AnalysedExpr child) {
|
||||
predicate guarded(StackVariable v, Stmt loopstart, AnalysedExpr child) {
|
||||
choice(v, loopstart, _) and
|
||||
loopstart.getChildStmt*() = child.getEnclosingStmt() and
|
||||
(definition(v, child) or exists(child.getNullSuccessor(v)))
|
||||
@@ -47,9 +47,7 @@ predicate addressLeak(Variable v, Stmt leak) {
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
LocalScopeVariable v, Stmt branch, AnalysedExpr cond, string context, string test,
|
||||
string testresult
|
||||
from StackVariable v, Stmt branch, AnalysedExpr cond, string context, string test, string testresult
|
||||
where
|
||||
choice(v, branch, context) and
|
||||
forall(ControlFlowNode def | definition(v, def) and definitionReaches(def, cond) |
|
||||
|
||||
@@ -23,14 +23,14 @@ predicate closeCall(FunctionCall fc, Variable v) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
predicate openDefinition(StackVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
|
||||
}
|
||||
|
||||
predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(LocalScopeVariable v | openDefinition(v, def) and node = def.getASuccessor())
|
||||
exists(StackVariable v | openDefinition(v, def) and node = def.getASuccessor())
|
||||
or
|
||||
exists(LocalScopeVariable v, ControlFlowNode mid |
|
||||
exists(StackVariable v, ControlFlowNode mid |
|
||||
openDefinition(v, def) and
|
||||
openReaches(def, mid) and
|
||||
not errorSuccessor(v, mid) and
|
||||
@@ -40,7 +40,7 @@ predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
|
||||
predicate assignedToFieldOrGlobal(StackVariable v, Assignment assign) {
|
||||
exists(Variable external |
|
||||
assign.getRValue() = v.getAnAccess() and
|
||||
assign.getLValue().(VariableAccess).getTarget() = external and
|
||||
@@ -48,7 +48,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
|
||||
)
|
||||
}
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret
|
||||
from StackVariable v, ControlFlowNode def, ReturnStmt ret
|
||||
where
|
||||
openDefinition(v, def) and
|
||||
openReaches(def, ret) and
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import FileClosed
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
predicate fopenDefinition(StackVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr))
|
||||
}
|
||||
|
||||
class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
class FOpenVariableReachability extends StackVariableReachabilityWithReassignment {
|
||||
FOpenVariableReachability() { this = "FOpenVariableReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
fopenDefinition(v, node)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
// node may be used in fopenReaches
|
||||
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
|
||||
fcloseCallOrIndirect(node, v) or
|
||||
@@ -88,15 +88,13 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
definitionBarrier(v, node)
|
||||
}
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The value from fopen at `def` is still held in Variable `v` upon entering `node`.
|
||||
*/
|
||||
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
predicate fopenVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(FOpenVariableReachability r |
|
||||
// reachability
|
||||
r.reachesTo(def, _, node, v)
|
||||
@@ -107,25 +105,23 @@ predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, Contro
|
||||
)
|
||||
}
|
||||
|
||||
class FOpenReachability extends LocalScopeVariableReachabilityExt {
|
||||
class FOpenReachability extends StackVariableReachabilityExt {
|
||||
FOpenReachability() { this = "FOpenReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
fopenDefinition(v, node)
|
||||
}
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { fopenDefinition(v, node) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
|
||||
) {
|
||||
isSource(source, v) and
|
||||
next = node.getASuccessor() and
|
||||
// the file (stored in any variable `v0`) opened at `source` is closed or
|
||||
// assigned to a global at node, or NULL checked on the edge node -> next.
|
||||
exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) |
|
||||
exists(StackVariable v0 | fopenVariableReaches(v0, source, node) |
|
||||
node.(AnalysedExpr).getNullSuccessor(v0) = next or
|
||||
fcloseCallOrIndirect(node, v0) or
|
||||
assignedToFieldOrGlobal(v0, node)
|
||||
@@ -142,11 +138,11 @@ predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(FOpenReachability r | r.reaches(def, _, node))
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
|
||||
// assigned to anything except a StackVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
|
||||
or
|
||||
exists(Expr midExpr, Function mid, int arg |
|
||||
// indirect assignment
|
||||
@@ -163,7 +159,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
from ControlFlowNode def, ReturnStmt ret
|
||||
where
|
||||
fopenReaches(def, ret) and
|
||||
not exists(LocalScopeVariable v |
|
||||
not exists(StackVariable v |
|
||||
fopenVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import cpp
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
|
||||
from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
|
||||
where
|
||||
checked = v.getAnAccess() and
|
||||
dereferenced(checked) and
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import cpp
|
||||
|
||||
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
|
||||
predicate negativeCheck(StackVariable v, ComparisonOperation op) {
|
||||
exists(int varindex, string constant, Literal lit |
|
||||
op.getChild(varindex) = v.getAnAccess() and
|
||||
op.getChild(1 - varindex) = lit and
|
||||
@@ -38,7 +38,7 @@ predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
|
||||
)
|
||||
}
|
||||
|
||||
from LocalScopeVariable v, ArrayExpr dangerous, Expr check
|
||||
from StackVariable v, ArrayExpr dangerous, Expr check
|
||||
where
|
||||
useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and
|
||||
negativeCheck(v, check) and
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import MemoryFreed
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
/**
|
||||
* 'call' is either a direct call to f, or a possible call to f
|
||||
@@ -97,18 +97,18 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
predicate allocationDefinition(StackVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr))
|
||||
}
|
||||
|
||||
class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
class AllocVariableReachability extends StackVariableReachabilityWithReassignment {
|
||||
AllocVariableReachability() { this = "AllocVariableReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
allocationDefinition(v, node)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
// node may be used in allocationReaches
|
||||
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
|
||||
freeCallOrIndirect(node, v) or
|
||||
@@ -117,15 +117,13 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
definitionBarrier(v, node)
|
||||
}
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The value from allocation `def` is still held in Variable `v` upon entering `node`.
|
||||
*/
|
||||
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
predicate allocatedVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(AllocVariableReachability r |
|
||||
// reachability
|
||||
r.reachesTo(def, _, node, v)
|
||||
@@ -136,25 +134,25 @@ predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, Co
|
||||
)
|
||||
}
|
||||
|
||||
class AllocReachability extends LocalScopeVariableReachabilityExt {
|
||||
class AllocReachability extends StackVariableReachabilityExt {
|
||||
AllocReachability() { this = "AllocReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) {
|
||||
allocationDefinition(v, node)
|
||||
}
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
|
||||
) {
|
||||
isSource(source, v) and
|
||||
next = node.getASuccessor() and
|
||||
// the memory (stored in any variable `v0`) allocated at `source` is freed or
|
||||
// assigned to a global at node, or NULL checked on the edge node -> next.
|
||||
exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) |
|
||||
exists(StackVariable v0 | allocatedVariableReaches(v0, source, node) |
|
||||
node.(AnalysedExpr).getNullSuccessor(v0) = next or
|
||||
freeCallOrIndirect(node, v0) or
|
||||
assignedToFieldOrGlobal(v0, node)
|
||||
@@ -171,11 +169,11 @@ predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(AllocReachability r | r.reaches(def, _, node))
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
|
||||
// assigned to anything except a StackVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
|
||||
or
|
||||
exists(Expr midExpr, Function mid, int arg |
|
||||
// indirect assignment
|
||||
@@ -192,7 +190,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
from ControlFlowNode def, ReturnStmt ret
|
||||
where
|
||||
allocationReaches(def, ret) and
|
||||
not exists(LocalScopeVariable v |
|
||||
not exists(StackVariable v |
|
||||
allocatedVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
|
||||
@@ -43,7 +43,7 @@ class FunctionWithNegativeReturn extends Function {
|
||||
predicate dangerousUse(IntegralReturnValue val, Expr use) {
|
||||
exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val)
|
||||
or
|
||||
exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae |
|
||||
exists(StackVariable v, ControlFlowNode def, ArrayExpr ae |
|
||||
exprDefinition(v, def, val) and
|
||||
use = ae.getArrayOffset() and
|
||||
not boundsChecked(v, use) and
|
||||
@@ -54,7 +54,7 @@ predicate dangerousUse(IntegralReturnValue val, Expr use) {
|
||||
val = use and
|
||||
use.getType().getUnderlyingType() instanceof PointerType
|
||||
or
|
||||
exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add |
|
||||
exists(StackVariable v, ControlFlowNode def, AddExpr add |
|
||||
exprDefinition(v, def, val) and
|
||||
definitionUsePair(v, def, use) and
|
||||
add.getAnOperand() = use and
|
||||
|
||||
@@ -60,7 +60,7 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
|
||||
pragma[nomagic]
|
||||
private predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
|
||||
exists(Expr mid |
|
||||
not v instanceof LocalScopeVariable and
|
||||
not v instanceof StackVariable and
|
||||
v.getAnAssignedValue() = mid and
|
||||
allocReaches0(mid, alloc, kind)
|
||||
)
|
||||
@@ -76,7 +76,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) {
|
||||
allocExprOrIndirect(alloc, kind) and
|
||||
e = alloc
|
||||
or
|
||||
exists(SsaDefinition def, LocalScopeVariable v |
|
||||
exists(SsaDefinition def, StackVariable v |
|
||||
// alloc via SSA
|
||||
allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and
|
||||
e = def.getAUse(v)
|
||||
|
||||
@@ -18,7 +18,7 @@ class MallocCall extends FunctionCall {
|
||||
Expr getAllocatedSize() {
|
||||
if this.getArgument(0) instanceof VariableAccess
|
||||
then
|
||||
exists(LocalScopeVariable v, ControlFlowNode def |
|
||||
exists(StackVariable v, ControlFlowNode def |
|
||||
definitionUsePair(v, def, this.getArgument(0)) and
|
||||
exprDefinition(v, def, result)
|
||||
)
|
||||
|
||||
@@ -20,11 +20,10 @@ class ReturnPointsToExpr extends PointsToExpr {
|
||||
ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this }
|
||||
}
|
||||
|
||||
from ReturnPointsToExpr ret, LocalVariable local, float confidence
|
||||
from ReturnPointsToExpr ret, StackVariable local, float confidence
|
||||
where
|
||||
ret.pointsTo() = local and
|
||||
ret.getReturnStmt().getEnclosingFunction() = local.getFunction() and
|
||||
not local.isStatic() and
|
||||
confidence = ret.confidence() and
|
||||
confidence > 0.01
|
||||
select ret,
|
||||
|
||||
@@ -20,11 +20,10 @@ class ScopeUtilityClass extends Class {
|
||||
Call getAUse() { result = this.getAConstructor().getACallToThisFunction() }
|
||||
}
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def
|
||||
from StackVariable v, ControlFlowNode def
|
||||
where
|
||||
definition(v, def) and
|
||||
not definitionUsePair(v, def, _) and
|
||||
not v.isStatic() and
|
||||
not v.getAnAccess().isAddressOfAccess() and
|
||||
// parameter initializers are not in the call-graph at the moment
|
||||
not v.(Parameter).getInitializer().getExpr() = def and
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
/** `e` is an expression that frees the memory pointed to by `v`. */
|
||||
predicate isFreeExpr(Expr e, LocalScopeVariable v) {
|
||||
predicate isFreeExpr(Expr e, StackVariable v) {
|
||||
exists(VariableAccess va | va.getTarget() = v |
|
||||
exists(FunctionCall fc | fc = e |
|
||||
fc.getTarget().hasGlobalOrStdName("free") and
|
||||
@@ -27,7 +27,7 @@ predicate isFreeExpr(Expr e, LocalScopeVariable v) {
|
||||
}
|
||||
|
||||
/** `e` is an expression that (may) dereference `v`. */
|
||||
predicate isDerefExpr(Expr e, LocalScopeVariable v) {
|
||||
predicate isDerefExpr(Expr e, StackVariable v) {
|
||||
v.getAnAccess() = e and dereferenced(e)
|
||||
or
|
||||
isDerefByCallExpr(_, _, e, v)
|
||||
@@ -39,27 +39,27 @@ predicate isDerefExpr(Expr e, LocalScopeVariable v) {
|
||||
* or a source code function that dereferences the relevant
|
||||
* parameter.
|
||||
*/
|
||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, LocalScopeVariable v) {
|
||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
|
||||
v.getAnAccess() = va and
|
||||
va = c.getAnArgumentSubExpr(i) and
|
||||
not c.passesByReference(i, va) and
|
||||
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
|
||||
}
|
||||
|
||||
class UseAfterFreeReachability extends LocalScopeVariableReachability {
|
||||
class UseAfterFreeReachability extends StackVariableReachability {
|
||||
UseAfterFreeReachability() { this = "UseAfterFree" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { isFreeExpr(node, v) }
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { isDerefExpr(node, v) }
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
definitionBarrier(v, node) or
|
||||
isFreeExpr(node, v)
|
||||
}
|
||||
}
|
||||
|
||||
from UseAfterFreeReachability r, LocalScopeVariable v, Expr free, Expr e
|
||||
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
|
||||
where r.reaches(free, v, e)
|
||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
|
||||
free, "here"
|
||||
|
||||
@@ -18,49 +18,39 @@ optimizing compiler.
|
||||
<recommendation>
|
||||
<p>
|
||||
Solutions to this problem can be thought of as falling into one of two
|
||||
categories: (1) rewrite the signed expression so that overflow cannot occur
|
||||
but the signedness remains, or (2) rewrite (or cast) the signed expression
|
||||
into unsigned form.
|
||||
categories:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Below we list examples of expressions where signed overflow may
|
||||
occur, along with proposed solutions. The list should not be
|
||||
considered exhaustive.
|
||||
</p>
|
||||
<ol>
|
||||
<li>Rewrite the signed expression so that overflow cannot occur
|
||||
but the signedness remains.</li>
|
||||
<li>Change the variables and all their uses to be unsigned.</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
Given <code>unsigned short i, delta</code> and <code>i + delta < i</code>,
|
||||
it is possible to rewrite it as <code>(unsigned short)(i + delta) < i</code>.
|
||||
Note that <code>i + delta</code>does not actually overflow, due to <code>int</code> promotion
|
||||
The following cases all fall into the first category.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given <code>unsigned short i, delta</code> and <code>i + delta < i</code>,
|
||||
it is also possible to rewrite it as <code>USHORT_MAX - delta</code>. It must be true
|
||||
that <code>delta > 0</code> and the <code>limits.h</code> or <code>climits</code>
|
||||
<ol>
|
||||
<li>
|
||||
Given <code>unsigned short n1, delta</code> and <code>n1 + delta < n1</code>,
|
||||
it is possible to rewrite it as <code>(unsigned short)(n1 + delta) < n1</code>.
|
||||
Note that <code>n1 + delta</code> does not actually overflow, due to <code>int</code> promotion.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Given <code>unsigned short n1, delta</code> and <code>n1 + delta < n1</code>,
|
||||
it is also possible to rewrite it as <code>n1 > USHORT_MAX - delta</code>. The
|
||||
<code>limits.h</code> or <code>climits</code> header must then be included.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Given <code>int n1, delta</code> and <code>n1 + delta < n1</code>,
|
||||
it is possible to rewrite it as <code>n1 > INT_MAX - delta</code>. It must be true
|
||||
that <code>delta >= 0</code> and the <code>limits.h</code> or <code>climits</code>
|
||||
header has been included.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given <code>int i, delta</code> and <code>i + delta < i</code>,
|
||||
it is possible to rewrite it as <code>INT_MAX - delta</code>. It must be true
|
||||
that <code>delta > 0</code> and the <code>limits.h</code> or <code>climits</code>
|
||||
header has been included.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given <code>int i, delta</code> and <code>i + delta < i</code>,
|
||||
it is also possible to rewrite it as <code>(unsigned)i + delta < i</code>.
|
||||
Note that program semantics are affected by this change.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given <code>int i, delta</code> and <code>i + delta < i</code>,
|
||||
it is also possible to rewrite it as <code>unsigned int i, delta</code> and
|
||||
<code>i + delta < i</code>. Note that program semantics are
|
||||
affected by this change.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
@@ -68,7 +58,7 @@ affected by this change.
|
||||
In the following example, even though <code>delta</code> has been declared
|
||||
<code>unsigned short</code>, C/C++ type promotion rules require that its
|
||||
type is promoted to the larger type used in the addition and comparison,
|
||||
namely a <code>signed int</code>. Addition is performed on
|
||||
namely a <code>signed int</code>. Addition is performed on
|
||||
signed integers, and may have undefined behavior if an overflow occurs.
|
||||
As a result, the entire (comparison) expression may also have an undefined
|
||||
result.
|
||||
@@ -87,10 +77,10 @@ are avoided.
|
||||
<sample src="SignedOverflowCheck-good1.cpp" />
|
||||
<p>
|
||||
In the following example, even though both <code>n</code> and <code>delta</code>
|
||||
have been declared <code>unsigned short</code>, both are promoted to
|
||||
have been declared <code>unsigned short</code>, both are promoted to
|
||||
<code>signed int</code> prior to addition. Because we started out with the
|
||||
narrower <code>short</code> type, the addition is guaranteed not to overflow
|
||||
and is therefore defined. But the fact that <code>n1 + delta</code> never
|
||||
and is therefore defined. But the fact that <code>n1 + delta</code> never
|
||||
overflows means that the condition <code>n1 + delta < n1</code> will never
|
||||
hold true, which likely is not what the programmer intended. (see also the
|
||||
<code>cpp/bad-addition-overflow-check</code> query).
|
||||
@@ -98,7 +88,7 @@ hold true, which likely is not what the programmer intended. (see also the
|
||||
<sample src="SignedOverflowCheck-bad2.cpp" />
|
||||
<p>
|
||||
The next example provides a solution to the previous one. Even though
|
||||
<code>i + delta</code> does not overflow, casting it to an
|
||||
<code>n1 + delta</code> does not overflow, casting it to an
|
||||
<code>unsigned short</code> truncates the addition modulo 2^16,
|
||||
so that <code>unsigned short</code> "wrap around" may now be observed.
|
||||
Furthermore, since the left-hand side is now of type <code>unsigned short</code>,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
private import semmle.code.cpp.commons.Exclusions
|
||||
|
||||
from RelationalOperation ro, AddExpr add, Expr expr1, Expr expr2
|
||||
where
|
||||
@@ -22,7 +23,7 @@ where
|
||||
ro.getAnOperand() = expr2 and
|
||||
globalValueNumber(expr1) = globalValueNumber(expr2) and
|
||||
add.getUnspecifiedType().(IntegralType).isSigned() and
|
||||
not exists(MacroInvocation mi | mi.getAnAffectedElement() = add) and
|
||||
not isFromMacroDefinition(ro) and
|
||||
exprMightOverflowPositively(add) and
|
||||
exists(Compilation c | c.getAFileCompiled() = ro.getFile() |
|
||||
not c.getAnArgument() = "-fwrapv" and
|
||||
|
||||
@@ -37,7 +37,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
|
||||
pathMightOverflow = false and
|
||||
source.(FunctionCall).getTarget().(Snprintf).returnsFullFormatLength()
|
||||
or
|
||||
exists(RangeSsaDefinition def, LocalScopeVariable v |
|
||||
exists(RangeSsaDefinition def, StackVariable v |
|
||||
flowsToDef(source, def, v, pathMightOverflow) and
|
||||
sink = def.getAUse(v)
|
||||
)
|
||||
@@ -63,9 +63,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
|
||||
* `pathMightOverflow` is true if there is an arithmetic operation
|
||||
* on the path that might overflow.
|
||||
*/
|
||||
predicate flowsToDef(
|
||||
Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
|
||||
) {
|
||||
predicate flowsToDef(Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow) {
|
||||
// Might the current definition overflow?
|
||||
exists(boolean otherMightOverflow | flowsToDefImpl(source, def, v, otherMightOverflow) |
|
||||
if defMightOverflow(def, v)
|
||||
@@ -86,7 +84,7 @@ predicate flowsToDef(
|
||||
* the path. But it is a good way to reduce the number of false positives.
|
||||
*/
|
||||
predicate flowsToDefImpl(
|
||||
Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
|
||||
Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow
|
||||
) {
|
||||
// Assignment or initialization: `e = v;`
|
||||
exists(Expr e |
|
||||
|
||||
@@ -12,24 +12,24 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
class UndefReachability extends LocalScopeVariableReachability {
|
||||
class UndefReachability extends StackVariableReachability {
|
||||
UndefReachability() { this = "UndefReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) {
|
||||
candidateVariable(v) and
|
||||
node = v.getParentScope() and
|
||||
not v instanceof Parameter and
|
||||
not v.hasInitializer()
|
||||
}
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
candidateVariable(v) and
|
||||
node = v.getAnAccess()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
node.(AssignExpr).getLValue() = v.getAnAccess()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
import semmle.code.cpp.commons.NullTermination
|
||||
|
||||
/**
|
||||
@@ -22,10 +22,10 @@ DeclStmt declWithNoInit(LocalVariable v) {
|
||||
not exists(v.getInitializer())
|
||||
}
|
||||
|
||||
class ImproperNullTerminationReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
class ImproperNullTerminationReachability extends StackVariableReachabilityWithReassignment {
|
||||
ImproperNullTerminationReachability() { this = "ImproperNullTerminationReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
node = declWithNoInit(v)
|
||||
or
|
||||
exists(Call c, VariableAccess va |
|
||||
@@ -36,12 +36,12 @@ class ImproperNullTerminationReachability extends LocalScopeVariableReachability
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
node.(VariableAccess).getTarget() = v and
|
||||
variableMustBeNullTerminated(node)
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
exprDefinition(v, node, _) or
|
||||
mayAddNullTerminator(node, v.getAnAccess()) or
|
||||
isSinkActual(node, v) // only report first use
|
||||
|
||||
@@ -42,10 +42,8 @@ predicate hasNontrivialConversion(Expr e) {
|
||||
hasNontrivialConversion(e.getConversion())
|
||||
}
|
||||
|
||||
from LocalScopeVariable var, VariableAccess va, ReturnStmt r
|
||||
from StackVariable var, VariableAccess va, ReturnStmt r
|
||||
where
|
||||
not var.isStatic() and
|
||||
not var.isThreadLocal() and
|
||||
not var.getUnspecifiedType() instanceof ReferenceType and
|
||||
not r.isFromUninstantiatedTemplate(_) and
|
||||
va = var.getAnAccess() and
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
/**
|
||||
* Auxiliary predicate: Types that don't require initialization
|
||||
@@ -40,23 +40,17 @@ DeclStmt declWithNoInit(LocalVariable v) {
|
||||
result.getADeclaration() = v and
|
||||
not exists(v.getInitializer()) and
|
||||
/* The type of the variable is not stack-allocated. */
|
||||
not allocatedType(v.getType()) and
|
||||
/* The variable is not static (otherwise it is zeroed). */
|
||||
not v.isStatic() and
|
||||
/* The variable is not extern (otherwise it is zeroed). */
|
||||
not v.hasSpecifier("extern")
|
||||
not allocatedType(v.getType())
|
||||
}
|
||||
|
||||
class UninitialisedLocalReachability extends LocalScopeVariableReachability {
|
||||
class UninitialisedLocalReachability extends StackVariableReachability {
|
||||
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
node = declWithNoInit(v)
|
||||
}
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVarActual(v, node) }
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
// only report the _first_ possibly uninitialized use
|
||||
useOfVarActual(v, node) or
|
||||
definitionBarrier(v, node)
|
||||
|
||||
@@ -84,10 +84,10 @@ predicate hasZeroParamDecl(Function f) {
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
predicate isCompiledAsC(Function f) {
|
||||
exists(File file | file.compiledAsC() |
|
||||
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
|
||||
)
|
||||
predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
from FunctionCall fc, Function f, Parameter p
|
||||
@@ -95,7 +95,7 @@ where
|
||||
f = fc.getTarget() and
|
||||
p = f.getAParameter() and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
not f.isVarargs() and
|
||||
not f instanceof BuiltInFunction and
|
||||
p.getIndex() < fc.getNumberOfArguments() and
|
||||
|
||||
@@ -24,10 +24,10 @@ predicate hasZeroParamDecl(Function f) {
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
predicate isCompiledAsC(Function f) {
|
||||
exists(File file | file.compiledAsC() |
|
||||
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
|
||||
)
|
||||
predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
from FunctionCall fc, Function f
|
||||
@@ -36,7 +36,7 @@ where
|
||||
not f.isVarargs() and
|
||||
not f instanceof BuiltInFunction and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
// There is an explicit declaration of the function whose parameter count is larger
|
||||
// than the number of call arguments
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
|
||||
@@ -25,10 +25,10 @@ predicate hasZeroParamDecl(Function f) {
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
predicate isCompiledAsC(Function f) {
|
||||
exists(File file | file.compiledAsC() |
|
||||
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
|
||||
)
|
||||
predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
from FunctionCall fc, Function f
|
||||
@@ -36,7 +36,7 @@ where
|
||||
f = fc.getTarget() and
|
||||
not f.isVarargs() and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
exists(f.getBlock()) and
|
||||
// There must not exist a declaration with the number of parameters
|
||||
// at least as large as the number of call arguments
|
||||
|
||||
@@ -16,7 +16,7 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
|
||||
predicate hasUpperBound(VariableAccess offsetExpr) {
|
||||
exists(BasicBlock controlled, LocalScopeVariable offsetVar, SsaDefinition def |
|
||||
exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def |
|
||||
controlled.contains(offsetExpr) and
|
||||
linearBoundControls(controlled, def, offsetVar) and
|
||||
offsetExpr = def.getAUse(offsetVar)
|
||||
@@ -24,7 +24,7 @@ predicate hasUpperBound(VariableAccess offsetExpr) {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, LocalScopeVariable offsetVar) {
|
||||
predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, StackVariable offsetVar) {
|
||||
exists(GuardCondition guard, boolean branch |
|
||||
guard.controls(controlled, branch) and
|
||||
cmpWithLinearBound(guard, def.getAUse(offsetVar), Lesser(), branch)
|
||||
|
||||
@@ -44,7 +44,7 @@ Element friendlyLoc(Expr e) {
|
||||
not e instanceof Access and not e instanceof Call and result = e
|
||||
}
|
||||
|
||||
from Loop l, RelationalOperation rel, Expr small, Expr large
|
||||
from Loop l, RelationalOperation rel, VariableAccess small, Expr large
|
||||
where
|
||||
small = rel.getLesserOperand() and
|
||||
large = rel.getGreaterOperand() and
|
||||
@@ -60,7 +60,7 @@ where
|
||||
not getComparisonSize(large.(SubExpr).getLeftOperand().getExplicitlyConverted()) <= getComparisonSize(small) and
|
||||
not getComparisonSize(large.(RShiftExpr).getLeftOperand().getExplicitlyConverted()) <= getComparisonSize(small) and
|
||||
// ignore loop-invariant smaller variables
|
||||
loopVariant(small.getAChild*(), l)
|
||||
loopVariant(small, l)
|
||||
select rel,
|
||||
"Comparison between $@ of type " + small.getType().getName() + " and $@ of wider type " +
|
||||
large.getType().getName() + ".", friendlyLoc(small), small.toString(), friendlyLoc(large),
|
||||
|
||||
@@ -82,7 +82,7 @@ FunctionCall stat(Expr path, Expr buf) {
|
||||
predicate referenceTo(Expr source, Expr use) {
|
||||
source = use
|
||||
or
|
||||
exists(SsaDefinition def, LocalScopeVariable v |
|
||||
exists(SsaDefinition def, StackVariable v |
|
||||
def.getAnUltimateDefiningValue(v) = source and def.getAUse(v) = use
|
||||
)
|
||||
}
|
||||
@@ -109,9 +109,7 @@ where
|
||||
)
|
||||
) and
|
||||
// checkUse and opUse refer to the same SSA variable
|
||||
exists(SsaDefinition def, LocalScopeVariable v |
|
||||
def.getAUse(v) = checkUse and def.getAUse(v) = opUse
|
||||
) and
|
||||
exists(SsaDefinition def, StackVariable v | def.getAUse(v) = checkUse and def.getAUse(v) = opUse) and
|
||||
// opUse looks like an operation on a filename
|
||||
fc = filenameOperation(opUse) and
|
||||
// the return value of check is used (possibly with one step of
|
||||
|
||||
@@ -100,9 +100,9 @@ Type baseType(Type t) {
|
||||
*/
|
||||
predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) {
|
||||
// Reaching definitions.
|
||||
if exists(SsaDefinition def, LocalScopeVariable v | use = def.getAUse(v))
|
||||
if exists(SsaDefinition def, StackVariable v | use = def.getAUse(v))
|
||||
then
|
||||
exists(SsaDefinition def, LocalScopeVariable v | use = def.getAUse(v) |
|
||||
exists(SsaDefinition def, StackVariable v | use = def.getAUse(v) |
|
||||
defSourceType(def, v, sourceType, sourceLoc)
|
||||
)
|
||||
else
|
||||
@@ -137,7 +137,7 @@ predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) {
|
||||
* Holds if there is a pointer expression with type `sourceType` at
|
||||
* location `sourceLoc` which might define the value of `v` at `def`.
|
||||
*/
|
||||
predicate defSourceType(SsaDefinition def, LocalScopeVariable v, Type sourceType, Location sourceLoc) {
|
||||
predicate defSourceType(SsaDefinition def, StackVariable v, Type sourceType, Location sourceLoc) {
|
||||
exprSourceType(def.getDefiningValue(v), sourceType, sourceLoc)
|
||||
or
|
||||
defSourceType(def.getAPhiInput(v), v, sourceType, sourceLoc)
|
||||
|
||||
@@ -20,10 +20,9 @@ class ReturnPointsToExpr extends PointsToExpr {
|
||||
ReturnStmt getReturnStmt() { result.getExpr() = this }
|
||||
}
|
||||
|
||||
from ReturnPointsToExpr ret, LocalVariable dest
|
||||
from ReturnPointsToExpr ret, StackVariable dest
|
||||
where
|
||||
ret.pointsTo() = dest and
|
||||
ret.getReturnStmt().getParentStmt().getEnclosingFunction() = dest.getFunction() and
|
||||
not dest.isStatic()
|
||||
ret.getReturnStmt().getParentStmt().getEnclosingFunction() = dest.getFunction()
|
||||
select ret.getReturnStmt(),
|
||||
"AV Rule 111: A function shall not return a pointer or reference to a non-static local object."
|
||||
|
||||
@@ -13,6 +13,11 @@ Element stmtEnclosingElement(Stmt s) {
|
||||
/**
|
||||
* Gets the enclosing element of expression `e`.
|
||||
*/
|
||||
// The `pragma[nomagic]` is a workaround to prevent this cached stage (and all
|
||||
// subsequent stages) from being evaluated twice. See QL-888. It has the effect
|
||||
// of making the `Conversion` class predicate get the same optimization in all
|
||||
// queries.
|
||||
pragma[nomagic]
|
||||
cached
|
||||
Element exprEnclosingElement(Expr e) {
|
||||
result = exprEnclosingElement(e.getParent())
|
||||
|
||||
@@ -307,8 +307,8 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Local variables can be static; use the `isStatic` member predicate to
|
||||
* detect those.
|
||||
* See also `StackVariable`, which is the class of local-scope variables
|
||||
* without statics and thread-locals.
|
||||
*/
|
||||
class LocalScopeVariable extends Variable, @localscopevariable {
|
||||
/** Gets the function to which this variable belongs. */
|
||||
@@ -316,12 +316,21 @@ class LocalScopeVariable extends Variable, @localscopevariable {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `LocalScopeVariable` instead.
|
||||
* A C/C++ variable with _automatic storage duration_. In other words, a
|
||||
* function parameter or a local variable that is not static or thread-local.
|
||||
* For example, the variables `a` and `b` in the following code.
|
||||
* ```
|
||||
* void myFunction(int a) {
|
||||
* int b;
|
||||
* static int c;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
deprecated class StackVariable extends Variable {
|
||||
StackVariable() { this instanceof LocalScopeVariable }
|
||||
|
||||
Function getFunction() { result = this.(LocalScopeVariable).getFunction() }
|
||||
class StackVariable extends LocalScopeVariable {
|
||||
StackVariable() {
|
||||
not this.isStatic() and
|
||||
not this.isThreadLocal()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,7 +505,7 @@ class TemplateVariable extends Variable {
|
||||
* `myTemplateFunction<T>`:
|
||||
* ```
|
||||
* void myFunction() {
|
||||
* T a;
|
||||
* float a;
|
||||
* }
|
||||
*
|
||||
* template<type T>
|
||||
@@ -509,9 +518,6 @@ class TemplateVariable extends Variable {
|
||||
* myTemplateFunction<int>();
|
||||
* ```
|
||||
*/
|
||||
class SemanticStackVariable extends LocalScopeVariable {
|
||||
SemanticStackVariable() {
|
||||
not this.isStatic() and
|
||||
not this.isFromUninstantiatedTemplate(_)
|
||||
}
|
||||
class SemanticStackVariable extends StackVariable {
|
||||
SemanticStackVariable() { not this.isFromUninstantiatedTemplate(_) }
|
||||
}
|
||||
|
||||
@@ -94,11 +94,18 @@ predicate functionContainsPreprocCode(Function f) {
|
||||
* ```
|
||||
*/
|
||||
predicate isFromMacroDefinition(Element e) {
|
||||
exists(MacroInvocation mi |
|
||||
// e is in mi
|
||||
exists(MacroInvocation mi, Location eLocation, Location miLocation |
|
||||
mi.getAnExpandedElement() = e and
|
||||
// and e was apparently not passed in as a macro parameter
|
||||
e.getLocation().getStartLine() = mi.getLocation().getStartLine() and
|
||||
e.getLocation().getStartColumn() = mi.getLocation().getStartColumn()
|
||||
eLocation = e.getLocation() and
|
||||
miLocation = mi.getLocation() and
|
||||
// If the location of `e` coincides with the macro invocation, then `e` did
|
||||
// not come from a macro argument. The inequalities here could also be
|
||||
// equalities, but that confuses the join orderer into joining on the source
|
||||
// locations too early.
|
||||
// There are cases where the start location of a non-argument element comes
|
||||
// right after the invocation's open parenthesis, so it appears to be more
|
||||
// robust to match on the end location instead.
|
||||
eLocation.getEndLine() >= miLocation.getEndLine() and
|
||||
eLocation.getEndColumn() >= miLocation.getEndColumn()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ private import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
private import semmle.code.cpp.models.implementations.Strcat
|
||||
|
||||
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) {
|
||||
exists(LocalScopeVariable v0, Expr val |
|
||||
exists(StackVariable v0, Expr val |
|
||||
exprDefinition(v0, e, val) and
|
||||
val.getAChild*() = va and
|
||||
mayAddNullTerminator(e0, v0.getAnAccess())
|
||||
@@ -41,7 +41,7 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) {
|
||||
or
|
||||
// Assignment to non-stack variable
|
||||
exists(AssignExpr ae | e = ae |
|
||||
not ae.getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable and
|
||||
not ae.getLValue().(VariableAccess).getTarget() instanceof StackVariable and
|
||||
ae.getRValue().getAChild*() = va
|
||||
)
|
||||
or
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
private import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
private import semmle.code.cpp.dataflow.EscapesTree
|
||||
|
||||
/**
|
||||
@@ -108,7 +108,7 @@ library class DefOrUse extends ControlFlowNodeBase {
|
||||
/*
|
||||
* Implementation detail: this predicate and its private auxiliary
|
||||
* predicates are instances of the more general predicates in
|
||||
* LocalScopeVariableReachability.qll, and should be kept in sync.
|
||||
* StackVariableReachability.qll, and should be kept in sync.
|
||||
*
|
||||
* Unfortunately, caching of abstract predicates does not work well, so the
|
||||
* predicates are duplicated for now.
|
||||
|
||||
@@ -371,7 +371,7 @@ private int int_value(Expr e) {
|
||||
/** An `SsaDefinition` with an additional predicate `isLt`. */
|
||||
class GuardedSsa extends SsaDefinition {
|
||||
/** Holds if this `SsaDefinition` is guarded such that `this(var) < gt + k` is `testIsTrue` in `block`. */
|
||||
predicate isLt(LocalScopeVariable var, Expr gt, int k, BasicBlock block, boolean testIsTrue) {
|
||||
predicate isLt(StackVariable var, Expr gt, int k, BasicBlock block, boolean testIsTrue) {
|
||||
exists(Expr luse, GuardCondition test | this.getAUse(var) = luse |
|
||||
test.ensuresLt(luse, gt, k, block, testIsTrue)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachability` instead.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachability` instead.
|
||||
*
|
||||
* A reachability analysis for control-flow nodes involving stack variables.
|
||||
* This defines sources, sinks, and any other configurable aspect of the
|
||||
* analysis. Multiple analyses can coexist. To create an analysis, extend this
|
||||
@@ -18,7 +24,7 @@ import cpp
|
||||
* Then, to query whether there is flow between some source and sink, call the
|
||||
* `reaches` predicate on an instance of `MyAnalysisConfiguration`.
|
||||
*/
|
||||
abstract class LocalScopeVariableReachability extends string {
|
||||
abstract deprecated class LocalScopeVariableReachability extends string {
|
||||
bindingset[this]
|
||||
LocalScopeVariableReachability() { length() >= 0 }
|
||||
|
||||
@@ -207,6 +213,8 @@ predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachabilityWithReassignment` instead.
|
||||
*
|
||||
* Reachability analysis for control-flow nodes involving stack variables.
|
||||
* Unlike `LocalScopeVariableReachability`, this analysis takes variable
|
||||
* reassignments into account.
|
||||
@@ -216,7 +224,7 @@ predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
* `isSource` and `isSink`, and that there is a `reachesTo` predicate in
|
||||
* addition to `reaches`.
|
||||
*/
|
||||
abstract class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability {
|
||||
abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability {
|
||||
bindingset[this]
|
||||
LocalScopeVariableReachabilityWithReassignment() { length() >= 0 }
|
||||
|
||||
@@ -314,12 +322,14 @@ abstract class LocalScopeVariableReachabilityWithReassignment extends LocalScope
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachabilityExt` instead.
|
||||
*
|
||||
* Same as `LocalScopeVariableReachability`, but `isBarrier` works on control-flow
|
||||
* edges rather than nodes and is therefore parameterized by the original
|
||||
* source node as well. Otherwise, this class is used like
|
||||
* `LocalScopeVariableReachability`.
|
||||
*/
|
||||
abstract class LocalScopeVariableReachabilityExt extends string {
|
||||
abstract deprecated class LocalScopeVariableReachabilityExt extends string {
|
||||
bindingset[this]
|
||||
LocalScopeVariableReachabilityExt() { length() >= 0 }
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ library class StandardSSA extends SSAHelper {
|
||||
/**
|
||||
* A definition of one or more SSA variables, including phi node definitions.
|
||||
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
||||
* an `SsaDefinition d` and a `LocalScopeVariable v`, written `(d, v)` in this
|
||||
* an `SsaDefinition d` and a `StackVariable v`, written `(d, v)` in this
|
||||
* documentation. Note that definitions and uses can be coincident due to the
|
||||
* presence of parameter definitions and phi nodes.
|
||||
*
|
||||
* Not all `LocalScopeVariable`s of a function have SSA definitions. If the variable
|
||||
* Not all `StackVariable`s of a function have SSA definitions. If the variable
|
||||
* has its address taken, either explicitly or implicitly, then it is excluded
|
||||
* from analysis. `SsaDefinition`s are not generated in locations that are
|
||||
* statically seen to be unreachable.
|
||||
@@ -22,21 +22,19 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
SsaDefinition() { exists(StandardSSA x | x.ssa_defn(_, this, _, _)) }
|
||||
|
||||
/**
|
||||
* Gets a variable corresponding to an SSA LocalScopeVariable defined by
|
||||
* Gets a variable corresponding to an SSA StackVariable defined by
|
||||
* this definition.
|
||||
*/
|
||||
LocalScopeVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
|
||||
StackVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
|
||||
|
||||
/**
|
||||
* Gets a string representation of the SSA variable represented by the pair
|
||||
* `(this, v)`.
|
||||
*/
|
||||
string toString(LocalScopeVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
|
||||
string toString(StackVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
|
||||
|
||||
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
|
||||
VariableAccess getAUse(LocalScopeVariable v) {
|
||||
exists(StandardSSA x | result = x.getAUse(this, v))
|
||||
}
|
||||
VariableAccess getAUse(StackVariable v) { exists(StandardSSA x | result = x.getAUse(this, v)) }
|
||||
|
||||
/**
|
||||
* Gets the control-flow node for this definition. This will usually be the
|
||||
@@ -55,9 +53,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
|
||||
|
||||
/** Holds if this definition is a phi node for variable `v`. */
|
||||
predicate isPhiNode(LocalScopeVariable v) {
|
||||
exists(StandardSSA x | x.phi_node(v, this.(BasicBlock)))
|
||||
}
|
||||
predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) }
|
||||
|
||||
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
|
||||
|
||||
@@ -68,7 +64,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
* Holds if the SSA variable `(result, v)` is an input to the phi definition
|
||||
* `(this, v)`.
|
||||
*/
|
||||
SsaDefinition getAPhiInput(LocalScopeVariable v) {
|
||||
SsaDefinition getAPhiInput(StackVariable v) {
|
||||
this.isPhiNode(v) and
|
||||
result.reachesEndOfBB(v, this.(BasicBlock).getAPredecessor())
|
||||
}
|
||||
@@ -92,7 +88,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
* instead covered via `definedByParameter` and `getDefinition`,
|
||||
* respectively.
|
||||
*/
|
||||
Expr getDefiningValue(LocalScopeVariable v) {
|
||||
Expr getDefiningValue(StackVariable v) {
|
||||
exists(ControlFlowNode def | def = this.getDefinition() |
|
||||
def = v.getInitializer().getExpr() and def = result
|
||||
or
|
||||
@@ -117,7 +113,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
}
|
||||
|
||||
/** Holds if `(this, v)` reaches the end of basic block `b`. */
|
||||
predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) {
|
||||
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
|
||||
exists(StandardSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
}
|
||||
|
||||
@@ -125,7 +121,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
* Gets a definition that ultimately defines this variable and is not
|
||||
* itself a phi node.
|
||||
*/
|
||||
SsaDefinition getAnUltimateSsaDefinition(LocalScopeVariable v) {
|
||||
SsaDefinition getAnUltimateSsaDefinition(StackVariable v) {
|
||||
result = this.getAPhiInput(v).getAnUltimateSsaDefinition(v)
|
||||
or
|
||||
v = this.getAVariable() and
|
||||
@@ -138,7 +134,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
* recursing backwards through phi definitions. Not all definitions have a
|
||||
* defining expression---see the documentation for `getDefiningValue`.
|
||||
*/
|
||||
Expr getAnUltimateDefiningValue(LocalScopeVariable v) {
|
||||
Expr getAnUltimateDefiningValue(StackVariable v) {
|
||||
result = this.getAnUltimateSsaDefinition(v).getDefiningValue(v)
|
||||
}
|
||||
|
||||
@@ -149,7 +145,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
* `getAnUltimateSsaDefinition` to refer to a predicate named
|
||||
* `getAnUltimateSsaDefinition` in this class.
|
||||
*/
|
||||
deprecated Expr getAnUltimateDefinition(LocalScopeVariable v) {
|
||||
deprecated Expr getAnUltimateDefinition(StackVariable v) {
|
||||
result = this.getAnUltimateDefiningValue(v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,9 @@ private predicate dominanceFrontier(BasicBlock x, BasicBlock w) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended version of `definition` that also includes parameters but excludes
|
||||
* static variables.
|
||||
* Extended version of `definition` that also includes parameters.
|
||||
*/
|
||||
predicate var_definition(LocalScopeVariable v, ControlFlowNode node) {
|
||||
not v.isStatic() and
|
||||
predicate var_definition(StackVariable v, ControlFlowNode node) {
|
||||
not addressTakenVariable(v) and
|
||||
not unreachable(node) and
|
||||
(
|
||||
@@ -51,7 +49,7 @@ predicate var_definition(LocalScopeVariable v, ControlFlowNode node) {
|
||||
* analysis because the pointer could be used to change the value at
|
||||
* any moment.
|
||||
*/
|
||||
private predicate addressTakenVariable(LocalScopeVariable var) {
|
||||
private predicate addressTakenVariable(StackVariable var) {
|
||||
// If the type of the variable is a reference type, then it is safe (as
|
||||
// far as SSA is concerned) to take its address, because this does not
|
||||
// enable the variable to be modified indirectly. Obviously the
|
||||
@@ -71,7 +69,7 @@ private predicate addressTakenVariable(LocalScopeVariable var) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isReferenceVar(LocalScopeVariable v) {
|
||||
private predicate isReferenceVar(StackVariable v) {
|
||||
v.getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
@@ -79,22 +77,22 @@ private predicate isReferenceVar(LocalScopeVariable v) {
|
||||
* This predicate is the same as `var_definition`, but annotated with
|
||||
* the basic block and index of the control flow node.
|
||||
*/
|
||||
private predicate variableUpdate(LocalScopeVariable v, ControlFlowNode n, BasicBlock b, int i) {
|
||||
private predicate variableUpdate(StackVariable v, ControlFlowNode n, BasicBlock b, int i) {
|
||||
var_definition(v, n) and n = b.getNode(i)
|
||||
}
|
||||
|
||||
private predicate ssa_use(LocalScopeVariable v, VariableAccess node, BasicBlock b, int index) {
|
||||
private predicate ssa_use(StackVariable v, VariableAccess node, BasicBlock b, int index) {
|
||||
useOfVar(v, node) and b.getNode(index) = node
|
||||
}
|
||||
|
||||
private predicate live_at_start_of_bb(LocalScopeVariable v, BasicBlock b) {
|
||||
private predicate live_at_start_of_bb(StackVariable v, BasicBlock b) {
|
||||
exists(int i | ssa_use(v, _, b, i) | not exists(int j | variableUpdate(v, _, b, j) | j < i))
|
||||
or
|
||||
live_at_exit_of_bb(v, b) and not variableUpdate(v, _, b, _)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate live_at_exit_of_bb(LocalScopeVariable v, BasicBlock b) {
|
||||
private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) {
|
||||
live_at_start_of_bb(v, b.getASuccessor())
|
||||
}
|
||||
|
||||
@@ -110,12 +108,12 @@ library class SSAHelper extends int {
|
||||
* basic block `b`.
|
||||
*/
|
||||
cached
|
||||
predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) { none() }
|
||||
predicate custom_phi_node(StackVariable v, BasicBlock b) { none() }
|
||||
|
||||
/**
|
||||
* Remove any custom phi nodes that are invalid.
|
||||
*/
|
||||
private predicate sanitized_custom_phi_node(LocalScopeVariable v, BasicBlock b) {
|
||||
private predicate sanitized_custom_phi_node(StackVariable v, BasicBlock b) {
|
||||
custom_phi_node(v, b) and
|
||||
not addressTakenVariable(v) and
|
||||
not isReferenceVar(v) and
|
||||
@@ -127,7 +125,7 @@ library class SSAHelper extends int {
|
||||
* `b`.
|
||||
*/
|
||||
cached
|
||||
predicate phi_node(LocalScopeVariable v, BasicBlock b) {
|
||||
predicate phi_node(StackVariable v, BasicBlock b) {
|
||||
frontier_phi_node(v, b) or sanitized_custom_phi_node(v, b)
|
||||
}
|
||||
|
||||
@@ -138,13 +136,13 @@ library class SSAHelper extends int {
|
||||
* definitions). This is known as the iterated dominance frontier. See
|
||||
* Modern Compiler Implementation by Andrew Appel.
|
||||
*/
|
||||
private predicate frontier_phi_node(LocalScopeVariable v, BasicBlock b) {
|
||||
private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
|
||||
exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn_rec(v, x)) and
|
||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||
live_at_start_of_bb(v, b)
|
||||
}
|
||||
|
||||
private predicate ssa_defn_rec(LocalScopeVariable v, BasicBlock b) {
|
||||
private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
|
||||
phi_node(v, b)
|
||||
or
|
||||
variableUpdate(v, _, b, _)
|
||||
@@ -155,7 +153,7 @@ library class SSAHelper extends int {
|
||||
* position `index` in block `b`. This includes definitions from phi nodes.
|
||||
*/
|
||||
cached
|
||||
predicate ssa_defn(LocalScopeVariable v, ControlFlowNode node, BasicBlock b, int index) {
|
||||
predicate ssa_defn(StackVariable v, ControlFlowNode node, BasicBlock b, int index) {
|
||||
phi_node(v, b) and b.getStart() = node and index = -1
|
||||
or
|
||||
variableUpdate(v, node, b, index)
|
||||
@@ -179,7 +177,7 @@ library class SSAHelper extends int {
|
||||
* irrelevant indices at which there is no definition or use when traversing
|
||||
* basic blocks.
|
||||
*/
|
||||
private predicate defUseRank(LocalScopeVariable v, BasicBlock b, int rankix, int i) {
|
||||
private predicate defUseRank(StackVariable v, BasicBlock b, int rankix, int i) {
|
||||
i = rank[rankix](int j | ssa_defn(v, _, b, j) or ssa_use(v, _, b, j))
|
||||
}
|
||||
|
||||
@@ -189,7 +187,7 @@ library class SSAHelper extends int {
|
||||
* the extra rank at the end represents a position past the last node in
|
||||
* the block.
|
||||
*/
|
||||
private int lastRank(LocalScopeVariable v, BasicBlock b) {
|
||||
private int lastRank(StackVariable v, BasicBlock b) {
|
||||
result = max(int rankix | defUseRank(v, b, rankix, _)) + 1
|
||||
}
|
||||
|
||||
@@ -197,7 +195,7 @@ library class SSAHelper extends int {
|
||||
* Holds if SSA variable `(v, def)` is defined at rank index `rankix` in
|
||||
* basic block `b`.
|
||||
*/
|
||||
private predicate ssaDefRank(LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
|
||||
private predicate ssaDefRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
|
||||
exists(int i |
|
||||
ssa_defn(v, def, b, i) and
|
||||
defUseRank(v, b, rankix, i)
|
||||
@@ -210,9 +208,7 @@ library class SSAHelper extends int {
|
||||
* `v` that comes _at or after_ the reached node. Reaching a node means
|
||||
* that the definition is visible to any _use_ at that node.
|
||||
*/
|
||||
private predicate ssaDefReachesRank(
|
||||
LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix
|
||||
) {
|
||||
private predicate ssaDefReachesRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
|
||||
// A definition should not reach its own node unless a loop allows it.
|
||||
// When nodes are both definitions and uses for the same variable, the
|
||||
// use is understood to happen _before_ the definition. Phi nodes are
|
||||
@@ -227,7 +223,7 @@ library class SSAHelper extends int {
|
||||
|
||||
/** Holds if SSA variable `(v, def)` reaches the end of block `b`. */
|
||||
cached
|
||||
predicate ssaDefinitionReachesEndOfBB(LocalScopeVariable v, ControlFlowNode def, BasicBlock b) {
|
||||
predicate ssaDefinitionReachesEndOfBB(StackVariable v, ControlFlowNode def, BasicBlock b) {
|
||||
live_at_exit_of_bb(v, b) and ssaDefReachesRank(v, def, b, lastRank(v, b))
|
||||
or
|
||||
exists(BasicBlock idom |
|
||||
@@ -243,7 +239,7 @@ library class SSAHelper extends int {
|
||||
* reaches the end of `b`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate noDefinitionsSinceIDominator(LocalScopeVariable v, BasicBlock idom, BasicBlock b) {
|
||||
private predicate noDefinitionsSinceIDominator(StackVariable v, BasicBlock idom, BasicBlock b) {
|
||||
bbIDominates(idom, b) and // It is sufficient to traverse the dominator graph, cf. discussion above.
|
||||
live_at_exit_of_bb(v, b) and
|
||||
not ssa_defn(v, _, b, _)
|
||||
@@ -253,9 +249,7 @@ library class SSAHelper extends int {
|
||||
* Holds if SSA variable `(v, def)` reaches `use` within the same basic
|
||||
* block, where `use` is a `VariableAccess` of `v`.
|
||||
*/
|
||||
private predicate ssaDefinitionReachesUseWithinBB(
|
||||
LocalScopeVariable v, ControlFlowNode def, Expr use
|
||||
) {
|
||||
private predicate ssaDefinitionReachesUseWithinBB(StackVariable v, ControlFlowNode def, Expr use) {
|
||||
exists(BasicBlock b, int rankix, int i |
|
||||
ssaDefReachesRank(v, def, b, rankix) and
|
||||
defUseRank(v, b, rankix, i) and
|
||||
@@ -266,7 +260,7 @@ library class SSAHelper extends int {
|
||||
/**
|
||||
* Holds if SSA variable `(v, def)` reaches the control-flow node `use`.
|
||||
*/
|
||||
private predicate ssaDefinitionReaches(LocalScopeVariable v, ControlFlowNode def, Expr use) {
|
||||
private predicate ssaDefinitionReaches(StackVariable v, ControlFlowNode def, Expr use) {
|
||||
ssaDefinitionReachesUseWithinBB(v, def, use)
|
||||
or
|
||||
exists(BasicBlock b |
|
||||
@@ -281,7 +275,7 @@ library class SSAHelper extends int {
|
||||
* `(node, v)`.
|
||||
*/
|
||||
cached
|
||||
string toString(ControlFlowNode node, LocalScopeVariable v) {
|
||||
string toString(ControlFlowNode node, StackVariable v) {
|
||||
if phi_node(v, node.(BasicBlock))
|
||||
then result = "SSA phi(" + v.getName() + ")"
|
||||
else (
|
||||
@@ -294,7 +288,7 @@ library class SSAHelper extends int {
|
||||
* access of `v`.
|
||||
*/
|
||||
cached
|
||||
VariableAccess getAUse(ControlFlowNode def, LocalScopeVariable v) {
|
||||
VariableAccess getAUse(ControlFlowNode def, StackVariable v) {
|
||||
ssaDefinitionReaches(v, def, result) and
|
||||
ssa_use(v, result, _, _)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `LocalScopeVariableReachability` instead.
|
||||
*
|
||||
* A reachability analysis for control-flow nodes involving stack variables.
|
||||
* This defines sources, sinks, and any other configurable aspect of the
|
||||
* analysis. Multiple analyses can coexist. To create an analysis, extend this
|
||||
* class with a subclass whose characteristic predicate is a unique singleton
|
||||
* string. For example, write
|
||||
*
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends StackVariableReachability {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Override `isBarrier`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some source and sink, call the
|
||||
* `reaches` predicate on an instance of `MyAnalysisConfiguration`.
|
||||
*/
|
||||
abstract deprecated class StackVariableReachability extends string {
|
||||
abstract class StackVariableReachability extends string {
|
||||
bindingset[this]
|
||||
StackVariableReachability() { length() >= 0 }
|
||||
|
||||
@@ -24,13 +37,13 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
* uses basic blocks internally for better performance:
|
||||
*
|
||||
* ```
|
||||
* predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* reachesImpl(source, v, sink)
|
||||
* and
|
||||
* isSink(sink, v)
|
||||
* }
|
||||
*
|
||||
* predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* sink = source.getASuccessor() and isSource(source, v)
|
||||
* or
|
||||
* exists(ControlFlowNode mid | reachesImpl(source, v, mid) |
|
||||
@@ -44,7 +57,7 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
* In addition to using a better performing implementation, this analysis
|
||||
* accounts for loops where the condition is provably true upon entry.
|
||||
*/
|
||||
predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
/*
|
||||
* Implementation detail: the predicates in this class are a generalization of
|
||||
* those in DefinitionsAndUses.qll, and should be kept in sync.
|
||||
@@ -71,7 +84,8 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
}
|
||||
|
||||
private predicate bbSuccessorEntryReaches(
|
||||
BasicBlock bb, StackVariable v, ControlFlowNode node, boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
||||
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
|
||||
@@ -85,11 +99,22 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate bbEntryReachesLocally(BasicBlock bb, StackVariable v, ControlFlowNode node) {
|
||||
exists(int n | node = bb.getNode(n) and isSink(node, v) |
|
||||
not exists(int m | m < n | isBarrier(bb.getNode(m), v))
|
||||
private predicate bbEntryReachesLocally(
|
||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
||||
) {
|
||||
exists(int n |
|
||||
node = bb.getNode(n) and
|
||||
isSink(node, v)
|
||||
|
|
||||
not exists(this.firstBarrierIndexIn(bb, v))
|
||||
or
|
||||
n <= this.firstBarrierIndexIn(bb, v)
|
||||
)
|
||||
}
|
||||
|
||||
private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
|
||||
result = min(int m | isBarrier(bb.getNode(m), v))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,26 +138,32 @@ private predicate bbLoopEntryConditionAlwaysTrueAt(BasicBlock bb, int i, Control
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic block `pred` ends with a condition belonging to a loop, and that
|
||||
* condition is provably true upon entry. Basic block `succ` is a successor
|
||||
* of `pred`, and `skipsLoop` indicates whether `succ` is the false-successor
|
||||
* of `pred`.
|
||||
* Basic block `pred` contains all or part of the condition belonging to a loop,
|
||||
* and there is an edge from `pred` to `succ` that concludes the condition.
|
||||
* If the edge corrseponds with the loop condition being found to be `true`, then
|
||||
* `skipsLoop` is `false`. Otherwise the edge corresponds with the loop condition
|
||||
* being found to be `false` and `skipsLoop` is `true`. Non-concluding edges
|
||||
* within a complex loop condition are not matched by this predicate.
|
||||
*/
|
||||
private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
|
||||
BasicBlock pred, BasicBlock succ, boolean skipsLoop
|
||||
) {
|
||||
succ = pred.getASuccessor() and
|
||||
exists(ControlFlowNode last |
|
||||
last = pred.getEnd() and
|
||||
loopConditionAlwaysTrueUponEntry(_, last) and
|
||||
if succ = pred.getAFalseSuccessor() then skipsLoop = true else skipsLoop = false
|
||||
exists(Expr cond |
|
||||
loopConditionAlwaysTrueUponEntry(_, cond) and
|
||||
cond.getAChild*() = pred.getEnd() and
|
||||
succ = pred.getASuccessor() and
|
||||
not cond.getAChild*() = succ.getStart() and
|
||||
(
|
||||
succ = pred.getAFalseSuccessor() and
|
||||
skipsLoop = true
|
||||
or
|
||||
succ = pred.getATrueSuccessor() and
|
||||
skipsLoop = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use the corresponding predicate in
|
||||
* `LocalScopeVariableReachability` instead.
|
||||
*
|
||||
* Loop invariant for `bbSuccessorEntryReaches`:
|
||||
*
|
||||
* - `succ` is a successor of `pred`.
|
||||
@@ -146,7 +177,7 @@ private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
|
||||
* is provably true upon entry, then `succ` is not allowed to skip
|
||||
* that loop (`succSkipsFirstLoopAlwaysTrueUponEntry = false`).
|
||||
*/
|
||||
deprecated predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
BasicBlock pred, BasicBlock succ, boolean predSkipsFirstLoopAlwaysTrueUponEntry,
|
||||
boolean succSkipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
@@ -162,7 +193,7 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
// The edge from `pred` to `succ` is _not_ from a loop condition provably
|
||||
// true upon entry, so the values of `predSkipsFirstLoopAlwaysTrueUponEntry`
|
||||
// and `succSkipsFirstLoopAlwaysTrueUponEntry` must be the same.
|
||||
not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, _, _) and
|
||||
not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, _) and
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry = predSkipsFirstLoopAlwaysTrueUponEntry and
|
||||
// Moreover, if `pred` contains the entry point of a loop where the
|
||||
// condition is provably true upon entry, then `succ` is not allowed
|
||||
@@ -176,13 +207,16 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `LocalScopeVariableReachabilityWithReassignment` instead.
|
||||
*
|
||||
* Reachability analysis for control-flow nodes involving stack variables.
|
||||
* Unlike `StackVariableReachability`, this analysis takes variable
|
||||
* reassignments into account.
|
||||
*
|
||||
* This class is used like `StackVariableReachability`, except that
|
||||
* subclasses should override `isSourceActual` and `isSinkActual` instead of
|
||||
* `isSource` and `isSink`, and that there is a `reachesTo` predicate in
|
||||
* addition to `reaches`.
|
||||
*/
|
||||
abstract deprecated class StackVariableReachabilityWithReassignment extends StackVariableReachability {
|
||||
abstract class StackVariableReachabilityWithReassignment extends StackVariableReachability {
|
||||
bindingset[this]
|
||||
StackVariableReachabilityWithReassignment() { length() >= 0 }
|
||||
|
||||
@@ -199,19 +233,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
* performance:
|
||||
*
|
||||
* ```
|
||||
* predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* reachesImpl(source, v, sink)
|
||||
* and
|
||||
* isSinkActual(sink, v)
|
||||
* }
|
||||
*
|
||||
* predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* isSourceActual(source, v)
|
||||
* and
|
||||
* (
|
||||
* sink = source.getASuccessor()
|
||||
* or
|
||||
* exists(ControlFlowNode mid, StackVariable v0 | reachesImpl(source, v0, mid) |
|
||||
* exists(ControlFlowNode mid, SemanticStackVariable v0 | reachesImpl(source, v0, mid) |
|
||||
* // ordinary successor
|
||||
* not isBarrier(mid, v) and
|
||||
* sink = mid.getASuccessor() and
|
||||
@@ -228,7 +262,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
* In addition to using a better performing implementation, this analysis
|
||||
* accounts for loops where the condition is provably true upon entry.
|
||||
*/
|
||||
override predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
reachesTo(source, v, sink, _)
|
||||
}
|
||||
|
||||
@@ -236,7 +270,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
* As `reaches`, but also specifies the last variable it was reassigned to (`v0`).
|
||||
*/
|
||||
predicate reachesTo(
|
||||
ControlFlowNode source, StackVariable v, ControlFlowNode sink, StackVariable v0
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0
|
||||
) {
|
||||
exists(ControlFlowNode def |
|
||||
actualSourceReaches(source, v, def, v0) and
|
||||
@@ -246,17 +280,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
}
|
||||
|
||||
private predicate actualSourceReaches(
|
||||
ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
||||
) {
|
||||
isSourceActual(source, v) and def = source and v0 = v
|
||||
or
|
||||
exists(ControlFlowNode source1, StackVariable v1 | actualSourceReaches(source, v, source1, v1) |
|
||||
exists(ControlFlowNode source1, SemanticStackVariable v1 |
|
||||
actualSourceReaches(source, v, source1, v1)
|
||||
|
|
||||
reassignment(source1, v1, def, v0)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate reassignment(
|
||||
ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
||||
) {
|
||||
StackVariableReachability.super.reaches(source, v, def) and
|
||||
exprDefinition(v0, def, v.getAnAccess())
|
||||
@@ -278,13 +314,12 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `LocalScopeVariableReachabilityExt` instead.
|
||||
*
|
||||
* Same as `StackVariableReachability`, but `isBarrier` works on control-flow
|
||||
* edges rather than nodes and is therefore parameterized by the original
|
||||
* source node as well.
|
||||
* source node as well. Otherwise, this class is used like
|
||||
* `StackVariableReachability`.
|
||||
*/
|
||||
abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
abstract class StackVariableReachabilityExt extends string {
|
||||
bindingset[this]
|
||||
StackVariableReachabilityExt() { length() >= 0 }
|
||||
|
||||
@@ -300,7 +335,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
);
|
||||
|
||||
/** See `StackVariableReachability.reaches`. */
|
||||
predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
exists(BasicBlock bb, int i |
|
||||
isSource(source, v) and
|
||||
bb.getNode(i) = source and
|
||||
@@ -321,7 +356,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
}
|
||||
|
||||
private predicate bbSuccessorEntryReaches(
|
||||
ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node,
|
||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
||||
@@ -338,7 +373,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
}
|
||||
|
||||
private predicate bbEntryReachesLocally(
|
||||
ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node
|
||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
||||
) {
|
||||
isSource(source, v) and
|
||||
exists(int n | node = bb.getNode(n) and isSink(node, v) |
|
||||
|
||||
@@ -924,7 +924,7 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
|
||||
/*
|
||||
* Use primitive basic blocks in reachability analysis for better performance.
|
||||
* This is similar to the pattern used in e.g. `DefinitionsAndUses` and
|
||||
* `LocalScopeVariableReachability`.
|
||||
* `StackVariableReachability`.
|
||||
*/
|
||||
|
||||
exists(PrimitiveBasicBlock bb1, int pos1 | bb1.getNode(pos1) = valueOrDef |
|
||||
|
||||
@@ -61,7 +61,7 @@ predicate stackPointerFlowsToUse(Expr use, Type useType, Expr source, boolean is
|
||||
stackPointerFlowsToUse(use.(PointerAddExpr).getAnOperand(), useType, source, isLocal)
|
||||
or
|
||||
// Indirect use of a stack address.
|
||||
exists(SsaDefinition def, LocalScopeVariable var |
|
||||
exists(SsaDefinition def, StackVariable var |
|
||||
stackPointerFlowsToDef(def, var, useType, source, isLocal) and
|
||||
use = def.getAUse(var)
|
||||
)
|
||||
@@ -97,8 +97,7 @@ private PointerType getExprPtrType(Expr use) { result = use.getUnspecifiedType()
|
||||
|
||||
predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean isLocal) {
|
||||
// Stack variables
|
||||
exists(LocalScopeVariable var |
|
||||
not var.isStatic() and
|
||||
exists(StackVariable var |
|
||||
use = source and
|
||||
source = var.getAnAccess() and
|
||||
isLocal = true and
|
||||
@@ -140,7 +139,7 @@ predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean
|
||||
stackPointerFlowsToUse(use.(PointerDereferenceExpr).getOperand(), useType, source, isLocal)
|
||||
or
|
||||
// Indirect use of a stack reference, via a reference variable.
|
||||
exists(SsaDefinition def, LocalScopeVariable var |
|
||||
exists(SsaDefinition def, StackVariable var |
|
||||
stackReferenceFlowsToDef(def, var, useType, source, isLocal) and
|
||||
use = def.getAUse(var)
|
||||
)
|
||||
@@ -162,7 +161,7 @@ predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean
|
||||
* addresses through SSA definitions.
|
||||
*/
|
||||
predicate stackPointerFlowsToDef(
|
||||
SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal
|
||||
SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal
|
||||
) {
|
||||
stackPointerFlowsToUse(def.getDefiningValue(var), useType, source, isLocal)
|
||||
or
|
||||
@@ -184,7 +183,7 @@ predicate stackPointerFlowsToDef(
|
||||
* int&, rather than pointers.
|
||||
*/
|
||||
predicate stackReferenceFlowsToDef(
|
||||
SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal
|
||||
SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal
|
||||
) {
|
||||
// Check that the type of the variable is a reference type and delegate
|
||||
// the rest of the work to stackReferenceFlowsToDef_Impl.
|
||||
@@ -197,7 +196,7 @@ predicate stackReferenceFlowsToDef(
|
||||
* predicate.
|
||||
*/
|
||||
predicate stackReferenceFlowsToDef_Impl(
|
||||
SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal
|
||||
SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal
|
||||
) {
|
||||
stackReferenceFlowsToUse(def.getDefiningValue(var), useType, source, isLocal)
|
||||
or
|
||||
@@ -213,7 +212,7 @@ predicate stackReferenceFlowsToDef_Impl(
|
||||
}
|
||||
|
||||
/** The type of the variable is a reference type, such as int&. */
|
||||
predicate isReferenceVariable(LocalScopeVariable var) {
|
||||
predicate isReferenceVariable(StackVariable var) {
|
||||
var.getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
@@ -284,7 +283,7 @@ predicate memberFcnMightRunOnStack(MemberFunction fcn, Type useType) {
|
||||
predicate constructorMightRunOnStack(Constructor constructor) {
|
||||
exists(ConstructorCall call | call.getTarget() = constructor |
|
||||
// Call to a constructor from a stack variable's initializer.
|
||||
exists(LocalScopeVariable var | var.getInitializer().getExpr() = call)
|
||||
exists(StackVariable var | var.getInitializer().getExpr() = call)
|
||||
or
|
||||
// Call to a constructor from another constructor which might
|
||||
// also run on the stack.
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ private module ImplCommon {
|
||||
*/
|
||||
cached
|
||||
predicate read(Node node1, Content f, Node node2) {
|
||||
readStep(node1, f, node2) and storeStep(_, f, _)
|
||||
readStep(node1, f, node2)
|
||||
or
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
read0(call, kind, node1, f) and
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class FlowVar extends TFlowVar {
|
||||
* `FlowVar` instance for the uninitialized value of that variable.
|
||||
*/
|
||||
cached
|
||||
abstract predicate definedByInitialValue(LocalScopeVariable v);
|
||||
abstract predicate definedByInitialValue(StackVariable v);
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
cached
|
||||
@@ -268,7 +268,7 @@ module FlowVar_internal {
|
||||
* Holds if `sbb` is the `SubBasicBlock` where `v` receives its initial value.
|
||||
* See the documentation for `FlowVar.definedByInitialValue`.
|
||||
*/
|
||||
predicate blockVarDefinedByVariable(SubBasicBlock sbb, LocalScopeVariable v) {
|
||||
predicate blockVarDefinedByVariable(SubBasicBlock sbb, StackVariable v) {
|
||||
sbb = v.(Parameter).getFunction().getEntryPoint()
|
||||
or
|
||||
exists(DeclStmt declStmt |
|
||||
@@ -279,7 +279,7 @@ module FlowVar_internal {
|
||||
}
|
||||
|
||||
newtype TFlowVar =
|
||||
TSsaVar(SsaDefinition def, LocalScopeVariable v) {
|
||||
TSsaVar(SsaDefinition def, StackVariable v) {
|
||||
fullySupportedSsaVariable(v) and
|
||||
v = def.getAVariable()
|
||||
} or
|
||||
@@ -303,7 +303,7 @@ module FlowVar_internal {
|
||||
*/
|
||||
class SsaVar extends TSsaVar, FlowVar {
|
||||
SsaDefinition def;
|
||||
LocalScopeVariable v;
|
||||
StackVariable v;
|
||||
|
||||
SsaVar() { this = TSsaVar(def, v) }
|
||||
|
||||
@@ -343,7 +343,7 @@ module FlowVar_internal {
|
||||
|
||||
override predicate definedPartiallyAt(Expr e) { none() }
|
||||
|
||||
override predicate definedByInitialValue(LocalScopeVariable param) {
|
||||
override predicate definedByInitialValue(StackVariable param) {
|
||||
def.definedByParameter(param) and
|
||||
param = v
|
||||
}
|
||||
@@ -407,7 +407,7 @@ module FlowVar_internal {
|
||||
getAReachedBlockVarSBB(this).getANode() = p.getFunction()
|
||||
}
|
||||
|
||||
override predicate definedByInitialValue(LocalScopeVariable lsv) {
|
||||
override predicate definedByInitialValue(StackVariable lsv) {
|
||||
blockVarDefinedByVariable(sbb, lsv) and
|
||||
lsv = v
|
||||
}
|
||||
@@ -647,11 +647,8 @@ module FlowVar_internal {
|
||||
/**
|
||||
* A local variable that is uninitialized immediately after its declaration.
|
||||
*/
|
||||
class UninitializedLocalVariable extends LocalVariable {
|
||||
UninitializedLocalVariable() {
|
||||
not this.hasInitializer() and
|
||||
not this.isStatic()
|
||||
}
|
||||
class UninitializedLocalVariable extends LocalVariable, StackVariable {
|
||||
UninitializedLocalVariable() { not this.hasInitializer() }
|
||||
}
|
||||
|
||||
/** Holds if `va` may be an uninitialized access to `v`. */
|
||||
|
||||
@@ -62,11 +62,10 @@ abstract class CrementOperation extends UnaryArithmeticOperation {
|
||||
override predicate mayBeImpure() { any() }
|
||||
|
||||
override predicate mayBeGloballyImpure() {
|
||||
not exists(VariableAccess va, LocalScopeVariable v |
|
||||
not exists(VariableAccess va, StackVariable v |
|
||||
va = this.getOperand() and
|
||||
v = va.getTarget() and
|
||||
not va.getConversion+() instanceof ReferenceDereferenceExpr and
|
||||
not v.isStatic()
|
||||
not va.getConversion+() instanceof ReferenceDereferenceExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,10 @@ abstract class Assignment extends Operation {
|
||||
override predicate mayBeGloballyImpure() {
|
||||
this.getRValue().mayBeGloballyImpure()
|
||||
or
|
||||
not exists(VariableAccess va, LocalScopeVariable v |
|
||||
not exists(VariableAccess va, StackVariable v |
|
||||
va = this.getLValue() and
|
||||
v = va.getTarget() and
|
||||
not va.getConversion+() instanceof ReferenceDereferenceExpr and
|
||||
not v.isStatic()
|
||||
not va.getConversion+() instanceof ReferenceDereferenceExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ private module ImplCommon {
|
||||
*/
|
||||
cached
|
||||
predicate read(Node node1, Content f, Node node2) {
|
||||
readStep(node1, f, node2) and storeStep(_, f, _)
|
||||
readStep(node1, f, node2)
|
||||
or
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
read0(call, kind, node1, f) and
|
||||
|
||||
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
this = block.getInstruction(result)
|
||||
or
|
||||
this = rank[-result - 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
or
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getLineRank() {
|
||||
this = rank[result](Instruction instr |
|
||||
instr.getAST().getFile() = getAST().getFile() and
|
||||
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
this = block.getInstruction(result)
|
||||
or
|
||||
this = rank[-result - 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
or
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getLineRank() {
|
||||
this = rank[result](Instruction instr |
|
||||
instr.getAST().getFile() = getAST().getFile() and
|
||||
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
this = block.getInstruction(result)
|
||||
or
|
||||
this = rank[-result - 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
or
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getLineRank() {
|
||||
this = rank[result](Instruction instr |
|
||||
instr.getAST().getFile() = getAST().getFile() and
|
||||
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import AliasAnalysis
|
||||
private import SimpleSSAImports
|
||||
import SimpleSSAPublicImports
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@ import semmle.code.cpp.ir.implementation.raw.IR
|
||||
import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
@@ -32,7 +32,7 @@ class StringLiteral = Cpp::StringLiteral;
|
||||
|
||||
class Variable = Cpp::Variable;
|
||||
|
||||
class AutomaticVariable = Cpp::LocalScopeVariable;
|
||||
class AutomaticVariable = Cpp::StackVariable;
|
||||
|
||||
class StaticVariable = Cpp::Variable;
|
||||
|
||||
@@ -66,10 +66,7 @@ int getTypeSize(Type type) { result = type.getSize() }
|
||||
|
||||
int getPointerSize() { exists(Cpp::NullPointerType nullptr | result = nullptr.getSize()) }
|
||||
|
||||
predicate isVariableAutomatic(Variable var) {
|
||||
var instanceof Cpp::LocalScopeVariable and
|
||||
not var.(Cpp::LocalScopeVariable).isStatic()
|
||||
}
|
||||
predicate isVariableAutomatic(Cpp::StackVariable var) { any() }
|
||||
|
||||
string getStringLiteralText(StringLiteral s) {
|
||||
result = s.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||
|
||||
@@ -24,7 +24,7 @@ predicate nanExcludingComparison(ComparisonOperation guard, boolean polarity) {
|
||||
* by virtue of the guard in `def`.
|
||||
*/
|
||||
private predicate excludesNan(RangeSsaDefinition def, VariableAccess v) {
|
||||
exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, LocalScopeVariable lsv |
|
||||
exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, StackVariable lsv |
|
||||
def.isGuardPhi(inCond, guard, branch) and
|
||||
inCond.getTarget() = lsv and
|
||||
v = def.getAUse(lsv) and
|
||||
|
||||
@@ -31,7 +31,7 @@ library class RangeSSA extends SSAHelper {
|
||||
/**
|
||||
* Add a phi node on the out-edge of a guard.
|
||||
*/
|
||||
override predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) {
|
||||
override predicate custom_phi_node(StackVariable v, BasicBlock b) {
|
||||
guard_defn(v.getAnAccess(), _, b, _)
|
||||
}
|
||||
}
|
||||
@@ -67,19 +67,19 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
RangeSsaDefinition() { exists(RangeSSA x | x.ssa_defn(_, this, _, _)) }
|
||||
|
||||
/**
|
||||
* Gets a variable corresponding to a SSA LocalScopeVariable defined by
|
||||
* Gets a variable corresponding to a SSA StackVariable defined by
|
||||
* this definition.
|
||||
*/
|
||||
LocalScopeVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) }
|
||||
StackVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) }
|
||||
|
||||
/**
|
||||
* A string representation of the SSA variable represented by the pair
|
||||
* `(this, v)`.
|
||||
*/
|
||||
string toString(LocalScopeVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
|
||||
string toString(StackVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
|
||||
|
||||
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
|
||||
VariableAccess getAUse(LocalScopeVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
|
||||
VariableAccess getAUse(StackVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
|
||||
|
||||
/** Gets the control flow node for this definition. */
|
||||
ControlFlowNode getDefinition() { result = this }
|
||||
@@ -87,9 +87,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
|
||||
|
||||
/** Whether this definition is a phi node for variable `v`. */
|
||||
predicate isPhiNode(LocalScopeVariable v) {
|
||||
exists(RangeSSA x | x.phi_node(v, this.(BasicBlock)))
|
||||
}
|
||||
predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) }
|
||||
|
||||
/**
|
||||
* If this definition is a phi node corresponding to a guard,
|
||||
@@ -104,7 +102,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
/** Whether this definition is from a parameter */
|
||||
predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() }
|
||||
|
||||
RangeSsaDefinition getAPhiInput(LocalScopeVariable v) {
|
||||
RangeSsaDefinition getAPhiInput(StackVariable v) {
|
||||
this.isPhiNode(v) and
|
||||
exists(BasicBlock pred |
|
||||
pred = this.(BasicBlock).getAPredecessor() and
|
||||
@@ -137,7 +135,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
}
|
||||
|
||||
/** Gets the expression assigned to this SsaDefinition. */
|
||||
Expr getDefiningValue(LocalScopeVariable v) {
|
||||
Expr getDefiningValue(StackVariable v) {
|
||||
exists(ControlFlowNode def | def = this.getDefinition() |
|
||||
def = v.getInitializer().getExpr() and def = result
|
||||
or
|
||||
@@ -155,7 +153,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
)
|
||||
}
|
||||
|
||||
predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) {
|
||||
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
|
||||
exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ private predicate analyzableExpr(Expr e) {
|
||||
exists(exprMinVal(e.(Conversion).getExpr())) or
|
||||
// Also allow variable accesses, provided that they have SSA
|
||||
// information.
|
||||
exists(RangeSsaDefinition def, LocalScopeVariable v | e = def.getAUse(v))
|
||||
exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ private predicate analyzableExpr(Expr e) {
|
||||
* here.
|
||||
*/
|
||||
private predicate defDependsOnDef(
|
||||
RangeSsaDefinition def, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar
|
||||
RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
|
||||
) {
|
||||
// Definitions with a defining value.
|
||||
exists(Expr expr | assignmentDef(def, v, expr) | exprDependsOnDef(expr, srcDef, srcVar))
|
||||
@@ -171,7 +171,7 @@ private predicate defDependsOnDef(
|
||||
* Helper predicate for `defDependsOnDef`. This predicate matches
|
||||
* the structure of `getLowerBoundsImpl` and `getUpperBoundsImpl`.
|
||||
*/
|
||||
private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, LocalScopeVariable srcVar) {
|
||||
private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVariable srcVar) {
|
||||
exists(UnaryMinusExpr negateExpr | e = negateExpr |
|
||||
exprDependsOnDef(negateExpr.getOperand(), srcDef, srcVar)
|
||||
)
|
||||
@@ -226,7 +226,7 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, LocalScope
|
||||
* the structure of `getPhiLowerBounds` and `getPhiUpperBounds`.
|
||||
*/
|
||||
private predicate phiDependsOnDef(
|
||||
RangeSsaDefinition phi, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar
|
||||
RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
|
||||
) {
|
||||
exists(VariableAccess access, ComparisonOperation guard |
|
||||
access = v.getAnAccess() and
|
||||
@@ -241,19 +241,17 @@ private predicate phiDependsOnDef(
|
||||
|
||||
/** The transitive closure of `defDependsOnDef`. */
|
||||
private predicate defDependsOnDefTransitively(
|
||||
RangeSsaDefinition def, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar
|
||||
RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
|
||||
) {
|
||||
defDependsOnDef(def, v, srcDef, srcVar)
|
||||
or
|
||||
exists(RangeSsaDefinition midDef, LocalScopeVariable midVar |
|
||||
defDependsOnDef(def, v, midDef, midVar)
|
||||
|
|
||||
exists(RangeSsaDefinition midDef, StackVariable midVar | defDependsOnDef(def, v, midDef, midVar) |
|
||||
defDependsOnDefTransitively(midDef, midVar, srcDef, srcVar)
|
||||
)
|
||||
}
|
||||
|
||||
/** The set of definitions that depend recursively on themselves. */
|
||||
private predicate isRecursiveDef(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) {
|
||||
defDependsOnDefTransitively(def, v, def, v)
|
||||
}
|
||||
|
||||
@@ -271,7 +269,7 @@ private predicate isRecursiveDef(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
*
|
||||
* This predicate finds all the definitions in the first set.
|
||||
*/
|
||||
private predicate assignmentDef(RangeSsaDefinition def, LocalScopeVariable v, Expr expr) {
|
||||
private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) {
|
||||
v.getUnspecifiedType() instanceof ArithmeticType and
|
||||
(
|
||||
def = v.getInitializer().getExpr() and def = expr
|
||||
@@ -285,7 +283,7 @@ private predicate assignmentDef(RangeSsaDefinition def, LocalScopeVariable v, Ex
|
||||
}
|
||||
|
||||
/** See comment above sourceDef. */
|
||||
private predicate analyzableDef(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) {
|
||||
assignmentDef(def, v, _) or defDependsOnDef(def, v, _, _)
|
||||
}
|
||||
|
||||
@@ -613,7 +611,7 @@ private float getLowerBoundsImpl(Expr expr) {
|
||||
)
|
||||
or
|
||||
// Use SSA to get the lower bounds for a variable use.
|
||||
exists(RangeSsaDefinition def, LocalScopeVariable v | expr = def.getAUse(v) |
|
||||
exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) |
|
||||
result = getDefLowerBounds(def, v)
|
||||
)
|
||||
}
|
||||
@@ -766,7 +764,7 @@ private float getUpperBoundsImpl(Expr expr) {
|
||||
)
|
||||
or
|
||||
// Use SSA to get the upper bounds for a variable use.
|
||||
exists(RangeSsaDefinition def, LocalScopeVariable v | expr = def.getAUse(v) |
|
||||
exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) |
|
||||
result = getDefUpperBounds(def, v)
|
||||
)
|
||||
}
|
||||
@@ -860,7 +858,7 @@ private float boolConversionUpperBound(Expr expr) {
|
||||
* In this example, the lower bound of x is 0, but we can
|
||||
* use the guard to deduce that the lower bound is 2 inside the block.
|
||||
*/
|
||||
private float getPhiLowerBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
|
||||
private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
exists(
|
||||
VariableAccess access, ComparisonOperation guard, boolean branch, float defLB, float guardLB
|
||||
|
|
||||
@@ -877,7 +875,7 @@ private float getPhiLowerBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
|
||||
}
|
||||
|
||||
/** See comment for `getPhiLowerBounds`, above. */
|
||||
private float getPhiUpperBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
|
||||
private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
exists(
|
||||
VariableAccess access, ComparisonOperation guard, boolean branch, float defUB, float guardUB
|
||||
|
|
||||
@@ -894,7 +892,7 @@ private float getPhiUpperBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
|
||||
}
|
||||
|
||||
/** Only to be called by `getDefLowerBounds`. */
|
||||
private float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) {
|
||||
// Definitions with a defining value.
|
||||
exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr))
|
||||
or
|
||||
@@ -936,7 +934,7 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v
|
||||
}
|
||||
|
||||
/** Only to be called by `getDefUpperBounds`. */
|
||||
private float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) {
|
||||
// Definitions with a defining value.
|
||||
exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr))
|
||||
or
|
||||
@@ -982,7 +980,7 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v
|
||||
* done by `getDefLowerBoundsImpl`, but this is where widening is applied
|
||||
* to prevent the analysis from exploding due to a recursive definition.
|
||||
*/
|
||||
private float getDefLowerBounds(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
private float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) {
|
||||
exists(float newLB, float truncatedLB |
|
||||
newLB = getDefLowerBoundsImpl(def, v) and
|
||||
if varMinVal(v) <= newLB and newLB <= varMaxVal(v)
|
||||
@@ -1011,7 +1009,7 @@ private float getDefLowerBounds(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
}
|
||||
|
||||
/** See comment for `getDefLowerBounds`, above. */
|
||||
private float getDefUpperBounds(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
private float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) {
|
||||
exists(float newUB, float truncatedUB |
|
||||
newUB = getDefUpperBoundsImpl(def, v) and
|
||||
if varMinVal(v) <= newUB and newUB <= varMaxVal(v)
|
||||
@@ -1044,9 +1042,7 @@ private float getDefUpperBounds(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
* unanalyzable definitions (such as function parameters) and make their
|
||||
* bounds unknown.
|
||||
*/
|
||||
private predicate unanalyzableDefBounds(
|
||||
RangeSsaDefinition def, LocalScopeVariable v, float lb, float ub
|
||||
) {
|
||||
private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v, float lb, float ub) {
|
||||
v = def.getAVariable() and
|
||||
not analyzableDef(def, v) and
|
||||
lb = varMinVal(v) and
|
||||
@@ -1268,13 +1264,13 @@ private module SimpleRangeAnalysisCached {
|
||||
|
||||
/** Holds if the definition might overflow negatively. */
|
||||
cached
|
||||
predicate defMightOverflowNegatively(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
predicate defMightOverflowNegatively(RangeSsaDefinition def, StackVariable v) {
|
||||
getDefLowerBoundsImpl(def, v) < varMinVal(v)
|
||||
}
|
||||
|
||||
/** Holds if the definition might overflow positively. */
|
||||
cached
|
||||
predicate defMightOverflowPositively(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
predicate defMightOverflowPositively(RangeSsaDefinition def, StackVariable v) {
|
||||
getDefUpperBoundsImpl(def, v) > varMaxVal(v)
|
||||
}
|
||||
|
||||
@@ -1283,7 +1279,7 @@ private module SimpleRangeAnalysisCached {
|
||||
* negatively).
|
||||
*/
|
||||
cached
|
||||
predicate defMightOverflow(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) {
|
||||
defMightOverflowNegatively(def, v) or
|
||||
defMightOverflowPositively(def, v)
|
||||
}
|
||||
|
||||
@@ -170,8 +170,8 @@ private newtype GVNBase =
|
||||
GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or
|
||||
// If the local variable does not have a defining value, then
|
||||
// we use the SsaDefinition as its global value number.
|
||||
GVN_UndefinedLocalScopeVariable(LocalScopeVariable x, SsaDefinition def) {
|
||||
mk_UndefinedLocalScopeVariable(x, def, _)
|
||||
GVN_UndefinedStackVariable(StackVariable x, SsaDefinition def) {
|
||||
mk_UndefinedStackVariable(x, def, _)
|
||||
} or
|
||||
// Variables with no SSA information. As a crude (but safe)
|
||||
// approximation, we use `mostRecentSideEffect` to compute a definition
|
||||
@@ -235,8 +235,8 @@ class GVN extends GVNBase {
|
||||
if this instanceof GVN_FloatConst
|
||||
then result = "FloatConst"
|
||||
else
|
||||
if this instanceof GVN_UndefinedLocalScopeVariable
|
||||
then result = "UndefinedLocalScopeVariable"
|
||||
if this instanceof GVN_UndefinedStackVariable
|
||||
then result = "UndefinedStackVariable"
|
||||
else
|
||||
if this instanceof GVN_OtherVariable
|
||||
then result = "OtherVariable"
|
||||
@@ -307,7 +307,7 @@ private predicate mk_FloatConst(float val, Type t, Expr e) {
|
||||
t = e.getUnspecifiedType()
|
||||
}
|
||||
|
||||
private predicate analyzableLocalScopeVariable(VariableAccess access) {
|
||||
private predicate analyzableStackVariable(VariableAccess access) {
|
||||
strictcount(SsaDefinition def | def.getAUse(_) = access | def) = 1 and
|
||||
strictcount(SsaDefinition def, Variable v | def.getAUse(v) = access | v) = 1 and
|
||||
count(SsaDefinition def, Variable v |
|
||||
@@ -322,10 +322,10 @@ private predicate analyzableLocalScopeVariable(VariableAccess access) {
|
||||
// defining value. If there is a defining value, then there is no
|
||||
// need to generate a fresh `GVN` for the access because `globalValueNumber`
|
||||
// will follow the chain and use the GVN of the defining value.
|
||||
private predicate mk_UndefinedLocalScopeVariable(
|
||||
LocalScopeVariable x, SsaDefinition def, VariableAccess access
|
||||
private predicate mk_UndefinedStackVariable(
|
||||
StackVariable x, SsaDefinition def, VariableAccess access
|
||||
) {
|
||||
analyzableLocalScopeVariable(access) and
|
||||
analyzableStackVariable(access) and
|
||||
access = def.getAUse(x) and
|
||||
not exists(def.getDefiningValue(x))
|
||||
}
|
||||
@@ -515,16 +515,16 @@ GVN globalValueNumber(Expr e) {
|
||||
)
|
||||
or
|
||||
// Local variable with a defining value.
|
||||
exists(LocalScopeVariable x, SsaDefinition def |
|
||||
analyzableLocalScopeVariable(e) and
|
||||
exists(StackVariable x, SsaDefinition def |
|
||||
analyzableStackVariable(e) and
|
||||
e = def.getAUse(x) and
|
||||
result = globalValueNumber(def.getDefiningValue(x).getFullyConverted())
|
||||
)
|
||||
or
|
||||
// Local variable without a defining value.
|
||||
exists(LocalScopeVariable x, SsaDefinition def |
|
||||
mk_UndefinedLocalScopeVariable(x, def, e) and
|
||||
result = GVN_UndefinedLocalScopeVariable(x, def)
|
||||
exists(StackVariable x, SsaDefinition def |
|
||||
mk_UndefinedStackVariable(x, def, e) and
|
||||
result = GVN_UndefinedStackVariable(x, def)
|
||||
)
|
||||
or
|
||||
// Variable with no SSA information.
|
||||
@@ -594,7 +594,7 @@ private predicate analyzableConst(Expr e) {
|
||||
*/
|
||||
private predicate analyzableExpr(Expr e) {
|
||||
analyzableConst(e) or
|
||||
analyzableLocalScopeVariable(e) or
|
||||
analyzableStackVariable(e) or
|
||||
analyzableDotFieldAccess(e) or
|
||||
analyzablePointerFieldAccess(e) or
|
||||
analyzableImplicitThisFieldAccess(e) or
|
||||
|
||||
@@ -112,7 +112,7 @@ class UMLType extends UMLElement {
|
||||
else result = this.getUMLName()
|
||||
}
|
||||
|
||||
string toString() { result = this.getUMLName() }
|
||||
override string toString() { result = this.getUMLName() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,7 +163,7 @@ class UMLProperty extends UMLElement {
|
||||
result.getDeclaringType() = this.getUMLType().getCType()
|
||||
}
|
||||
|
||||
string toString() {
|
||||
override string toString() {
|
||||
if this.isEnumConstant()
|
||||
then result = "- <<enum constant>> " + this.getUMLName()
|
||||
else result = "- " + this.getUMLName()
|
||||
@@ -196,7 +196,7 @@ class UMLOperation extends UMLElement {
|
||||
result.getDeclaringType() = this.getUMLType().getCType()
|
||||
}
|
||||
|
||||
string toString() { result = "+ " + this.getUMLName() }
|
||||
override string toString() { result = "+ " + this.getUMLName() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +221,7 @@ class UMLAssociation extends UMLProperty {
|
||||
/**
|
||||
* Gets the C field corresponding to this property, if any.
|
||||
*/
|
||||
Field getCField() {
|
||||
override Field getCField() {
|
||||
result.hasName(this.getLabel()) and
|
||||
result.getDeclaringType() = this.getSource().getCType()
|
||||
}
|
||||
@@ -271,7 +271,7 @@ class UMLInheritance extends UMLElement {
|
||||
)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
override string toString() {
|
||||
result = this.getUMLClient().getUMLName() + " implements " + this.getUMLSupplier().getUMLName()
|
||||
}
|
||||
}
|
||||
@@ -303,5 +303,5 @@ class UMLPackage extends UMLElement {
|
||||
else result = this.getUMLName()
|
||||
}
|
||||
|
||||
string toString() { result = this.getUMLQualifiedName() }
|
||||
override string toString() { result = this.getUMLQualifiedName() }
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ import cpp
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
|
||||
/*
|
||||
* Count of number of uses of a LocalScopeVariable where no corresponding SSA definition exists,
|
||||
* Count of number of uses of a StackVariable where no corresponding SSA definition exists,
|
||||
* but at least one SSA definition for that variable can reach that use.
|
||||
* Should always be zero *regardless* of the input
|
||||
*/
|
||||
|
||||
select count(LocalScopeVariable v, Expr use |
|
||||
select count(StackVariable v, Expr use |
|
||||
exists(SsaDefinition def, BasicBlock db, BasicBlock ub |
|
||||
def.getAUse(v) = use and db.contains(def.getDefinition()) and ub.contains(use)
|
||||
|
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
|
||||
from SsaDefinition def, LocalScopeVariable var, Expr use
|
||||
from SsaDefinition def, StackVariable var, Expr use
|
||||
where def.getAUse(var) = use
|
||||
select def, def.toString(var), use
|
||||
|
||||
@@ -12,7 +12,7 @@ import semmle.code.cpp.controlflow.SSA
|
||||
* Should always be zero *regardless* of the input
|
||||
*/
|
||||
|
||||
select count(SsaDefinition d, LocalScopeVariable v, Expr u |
|
||||
select count(SsaDefinition d, StackVariable v, Expr u |
|
||||
d.getAUse(v) = u and
|
||||
not exists(BasicBlock bd, BasicBlock bu |
|
||||
bd.contains(mkElement(d).(ControlFlowNode)) and bu.contains(u)
|
||||
|
||||
@@ -8,7 +8,7 @@ import cpp
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
from GuardedSsa def, LocalScopeVariable var, Expr other, int k, int start, int end, string op
|
||||
from GuardedSsa def, StackVariable var, Expr other, int k, int start, int end, string op
|
||||
where
|
||||
exists(BasicBlock block |
|
||||
def.isLt(var, other, k, block, true) and op = "<"
|
||||
|
||||
@@ -8,8 +8,7 @@ import cpp
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
|
||||
from
|
||||
File file, SsaDefinition phi, LocalScopeVariable var, SsaDefinition input, int philine,
|
||||
int inputline
|
||||
File file, SsaDefinition phi, StackVariable var, SsaDefinition input, int philine, int inputline
|
||||
where
|
||||
phi.getAPhiInput(var) = input and
|
||||
file = phi.getLocation().getFile() and
|
||||
|
||||
@@ -12,7 +12,7 @@ import semmle.code.cpp.controlflow.SSA
|
||||
* Should always be zero *regardless* of the input
|
||||
*/
|
||||
|
||||
select count(SsaDefinition d1, SsaDefinition d2, Expr u, LocalScopeVariable v |
|
||||
select count(SsaDefinition d1, SsaDefinition d2, Expr u, StackVariable v |
|
||||
d1.getAUse(v) = u and
|
||||
d2.getAUse(v) = u and
|
||||
not d1 = d2
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
|
||||
from SsaDefinition def, LocalScopeVariable var, Expr use
|
||||
from SsaDefinition def, StackVariable var, Expr use
|
||||
where def.getAUse(var) = use
|
||||
select def, def.toString(var), use
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import semmle.code.cpp.dataflow.internal.FlowVar
|
||||
|
||||
from LocalScopeVariable var, VariableAccess va
|
||||
from Variable var, VariableAccess va
|
||||
where FlowVar_internal::mayBeUsedUninitialized(var, va)
|
||||
select var, va
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import semmle.code.cpp.dataflow.internal.FlowVar
|
||||
|
||||
from LocalScopeVariable var, VariableAccess va
|
||||
from Variable var, VariableAccess va
|
||||
where FlowVar_internal::mayBeUsedUninitialized(var, va)
|
||||
select var, va
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode d
|
||||
from StackVariable v, ControlFlowNode d
|
||||
where definition(v, d)
|
||||
select v, d
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
// Test that def/use algorithm is an instance of LocalScopeVariableReachability
|
||||
class MyDefOrUse extends LocalScopeVariableReachability {
|
||||
// Test that def/use algorithm is an instance of StackVariableReachability
|
||||
class MyDefOrUse extends StackVariableReachability {
|
||||
MyDefOrUse() { this = "MyDefUse" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { definition(v, node) }
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { definition(v, node) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVar(v, node) }
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVar(v, node) }
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
definitionBarrier(v, node)
|
||||
}
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
|
||||
}
|
||||
|
||||
predicate equivalence() {
|
||||
forall(LocalScopeVariable v, Expr first, Expr second | definitionUsePair(v, first, second) |
|
||||
forall(StackVariable v, Expr first, Expr second | definitionUsePair(v, first, second) |
|
||||
exists(MyDefOrUse x | x.reaches(first, v, second))
|
||||
) and
|
||||
forall(LocalScopeVariable v, Expr first, Expr second |
|
||||
forall(StackVariable v, Expr first, Expr second |
|
||||
exists(MyDefOrUse x | x.reaches(first, v, second))
|
||||
|
|
||||
definitionUsePair(v, first, second)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def, Expr e
|
||||
from StackVariable v, ControlFlowNode def, Expr e
|
||||
where exprDefinition(v, def, e)
|
||||
select v, def, e
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from LocalScopeVariable v, VariableAccess use
|
||||
from StackVariable v, VariableAccess use
|
||||
where useOfVar(v, use)
|
||||
select v, use
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import cpp
|
||||
|
||||
from LocalScopeVariable v, VariableAccess use
|
||||
from StackVariable v, VariableAccess use
|
||||
where
|
||||
useOfVarActual(v, use) and
|
||||
// Also check that `useOfVarActual` is a subset of `useOfVar`; if not
|
||||
// the query will not return any results
|
||||
forall(LocalScopeVariable v0, VariableAccess use0 | useOfVarActual(v0, use0) | useOfVar(v0, use0))
|
||||
forall(StackVariable v0, VariableAccess use0 | useOfVarActual(v0, use0) | useOfVar(v0, use0))
|
||||
select v, use
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def, Expr e
|
||||
from StackVariable v, ControlFlowNode def, Expr e
|
||||
where exprDefinition(v, def, e)
|
||||
select v, def, e
|
||||
|
||||
@@ -10,12 +10,12 @@ import cpp
|
||||
import semmle.code.cpp.rangeanalysis.RangeSSA
|
||||
|
||||
/*
|
||||
* Count of number of uses of a LocalScopeVariable where no corresponding SSA definition exists,
|
||||
* Count of number of uses of a StackVariable where no corresponding SSA definition exists,
|
||||
* but at least one SSA definition for that variable can reach that use.
|
||||
* Should always be zero *regardless* of the input
|
||||
*/
|
||||
|
||||
select count(LocalScopeVariable v, Expr use |
|
||||
select count(StackVariable v, Expr use |
|
||||
exists(RangeSsaDefinition def, BasicBlock db, BasicBlock ub |
|
||||
def.getAUse(v) = use and db.contains(def.getDefinition()) and ub.contains(use)
|
||||
|
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.RangeSSA
|
||||
|
||||
from RangeSsaDefinition def, LocalScopeVariable var, Expr use
|
||||
from RangeSsaDefinition def, StackVariable var, Expr use
|
||||
where def.getAUse(var) = use
|
||||
select def, def.toString(var), use
|
||||
|
||||
@@ -12,7 +12,7 @@ import semmle.code.cpp.rangeanalysis.RangeSSA
|
||||
* Should always be zero *regardless* of the input
|
||||
*/
|
||||
|
||||
select count(RangeSsaDefinition d, LocalScopeVariable v, Expr u |
|
||||
select count(RangeSsaDefinition d, StackVariable v, Expr u |
|
||||
d.getAUse(v) = u and
|
||||
not exists(BasicBlock bd, BasicBlock bu |
|
||||
bd.contains(mkElement(d).(ControlFlowNode)) and bu.contains(u)
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.RangeSSA
|
||||
|
||||
from
|
||||
RangeSsaDefinition phi, LocalScopeVariable var, RangeSsaDefinition input, int philine,
|
||||
int inputline
|
||||
from RangeSsaDefinition phi, StackVariable var, RangeSsaDefinition input, int philine, int inputline
|
||||
where
|
||||
phi.getAPhiInput(var) = input and
|
||||
philine = phi.getLocation().getStartLine() and
|
||||
|
||||
@@ -12,7 +12,7 @@ import semmle.code.cpp.rangeanalysis.RangeSSA
|
||||
* Should always be zero *regardless* of the input
|
||||
*/
|
||||
|
||||
select count(RangeSsaDefinition d1, RangeSsaDefinition d2, Expr u, LocalScopeVariable v |
|
||||
select count(RangeSsaDefinition d1, RangeSsaDefinition d2, Expr u, StackVariable v |
|
||||
d1.getAUse(v) = u and
|
||||
d2.getAUse(v) = u and
|
||||
not d1 = d2
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,13 +2,9 @@
|
||||
| file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | unsigned int | Field | | |
|
||||
| file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | void * | Field | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | __va_list_tag && | SemanticStackVariable | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | __va_list_tag && | StackVariable | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | address && | SemanticStackVariable | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | address && | StackVariable | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const __va_list_tag & | SemanticStackVariable | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const __va_list_tag & | StackVariable | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const address & | SemanticStackVariable | | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const address & | StackVariable | | |
|
||||
| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | Field | | |
|
||||
| variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
|
||||
| variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
|
||||
@@ -38,11 +34,10 @@
|
||||
| variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | GlobalVariable | | |
|
||||
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | LocalVariable | | |
|
||||
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | SemanticStackVariable | | |
|
||||
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | StackVariable | | |
|
||||
| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | LocalVariable | | static |
|
||||
| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | StackVariable | | static |
|
||||
| variables.cpp:48:9:48:12 | name | file://:0:0:0:0 | char * | Field | | |
|
||||
| variables.cpp:49:12:49:17 | number | file://:0:0:0:0 | long | Field | | |
|
||||
| variables.cpp:50:9:50:14 | street | file://:0:0:0:0 | char * | Field | | |
|
||||
| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | |
|
||||
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable | | static |
|
||||
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalVariable | | |
|
||||
|
||||
@@ -51,3 +51,7 @@ struct address {
|
||||
char* town;
|
||||
static char* country;
|
||||
};
|
||||
|
||||
void hasExtern() {
|
||||
extern int externInFunction;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user