Merge from master and resolve conflicts

This commit is contained in:
Dave Bartolomeo
2019-12-04 10:14:52 -07:00
240 changed files with 12094 additions and 9744 deletions

View File

@@ -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) |

View File

@@ -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

View File

@@ -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()
)

View File

@@ -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

View File

@@ -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

View File

@@ -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()
)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
)

View File

@@ -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,

View File

@@ -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

View File

@@ -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"

View File

@@ -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 &lt; i</code>,
it is possible to rewrite it as <code>(unsigned short)(i + delta)&nbsp;&lt;&nbsp;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 &lt; i</code>,
it is also possible to rewrite it as <code>USHORT_MAX - delta</code>. It must be true
that <code>delta &gt; 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 &lt; n1</code>,
it is possible to rewrite it as <code>(unsigned short)(n1 + delta)&nbsp;&lt;&nbsp;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 &lt; n1</code>,
it is also possible to rewrite it as <code>n1 &gt; 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 &lt; n1</code>,
it is possible to rewrite it as <code>n1 &gt; INT_MAX - delta</code>. It must be true
that <code>delta &gt;= 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 &lt; i</code>,
it is possible to rewrite it as <code>INT_MAX - delta</code>. It must be true
that <code>delta &gt; 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 &lt; i</code>,
it is also possible to rewrite it as <code>(unsigned)i + delta &lt; i</code>.
Note that program semantics are affected by this change.
</p>
<p>
Given <code>int i, delta</code> and <code>i + delta &lt; i</code>,
it is also possible to rewrite it as <code>unsigned int i, delta</code> and
<code>i + delta &lt; 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 &lt; 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>,

View File

@@ -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

View File

@@ -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 |

View File

@@ -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()
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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() |

View File

@@ -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

View File

@@ -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)

View File

@@ -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),

View File

@@ -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

View File

@@ -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)

View File

@@ -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."

View File

@@ -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())

View File

@@ -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(_) }
}

View File

@@ -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()
)
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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)
)

View File

@@ -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 }

View File

@@ -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)
}
}

View File

@@ -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, _, _)
}

View File

@@ -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) |

View File

@@ -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 |

View File

@@ -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.

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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

View File

@@ -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)
)
}

View File

@@ -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`. */

View File

@@ -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
)
}
}

View File

@@ -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
)
}
}

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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

View File

@@ -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()
}
/**

View File

@@ -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()
}
/**

View File

@@ -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()
}
/**

View File

@@ -1,5 +1,6 @@
import AliasAnalysis
private import SimpleSSAImports
import SimpleSSAPublicImports
private class IntValue = Ints::IntValue;

View File

@@ -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

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.internal.Overlap

View File

@@ -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", " ")

View File

@@ -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

View File

@@ -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))
}
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -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)
|

View File

@@ -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

View File

@@ -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)

View File

@@ -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 = "<"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,5 +1,5 @@
import cpp
from LocalScopeVariable v, ControlFlowNode d
from StackVariable v, ControlFlowNode d
where definition(v, d)
select v, d

View File

@@ -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)

View File

@@ -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

View File

@@ -1,5 +1,5 @@
import cpp
from LocalScopeVariable v, VariableAccess use
from StackVariable v, VariableAccess use
where useOfVar(v, use)
select v, use

View File

@@ -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

View File

@@ -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

View File

@@ -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)
|

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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 | | |

View File

@@ -51,3 +51,7 @@ struct address {
char* town;
static char* country;
};
void hasExtern() {
extern int externInFunction;
}