C++: Use StackVariable in SSA libraries

This means we'll no longer get SSA definitions for thread-local
local-scope variables.
This commit is contained in:
Jonas Jensen
2019-11-18 14:55:24 +01:00
parent c1ed908834
commit 95a333d28c
16 changed files with 61 additions and 76 deletions

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

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

@@ -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 cpp
from LocalScopeVariable v, ControlFlowNode d
from StackVariable v, ControlFlowNode d
where definition(v, d)
select v, d

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