mirror of
https://github.com/github/codeql.git
synced 2025-12-22 03:36:30 +01:00
Merge branch 'main' into fix-joins-in-using-expired-stack-address
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been
|
||||
deleted.
|
||||
|
||||
@@ -119,27 +119,67 @@ module SemanticExprConfig {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
|
||||
class SsaVariable instanceof IR::Instruction {
|
||||
SsaVariable() { super.hasMemoryResult() }
|
||||
newtype TSsaVariable =
|
||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
|
||||
|
||||
final string toString() { result = super.toString() }
|
||||
class SsaVariable extends TSsaVariable {
|
||||
string toString() { none() }
|
||||
|
||||
final Location getLocation() { result = super.getLocation() }
|
||||
Location getLocation() { none() }
|
||||
|
||||
IR::Instruction asInstruction() { none() }
|
||||
|
||||
IR::Operand asOperand() { none() }
|
||||
}
|
||||
|
||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v = sourceExpr }
|
||||
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
||||
IR::Instruction instr;
|
||||
|
||||
predicate phi(SsaVariable v) { v instanceof IR::PhiInstruction }
|
||||
SsaInstructionVariable() { this = TSsaInstruction(instr) }
|
||||
|
||||
SsaVariable getAPhiInput(SsaVariable v) { result = v.(IR::PhiInstruction).getAnInput() }
|
||||
final override string toString() { result = instr.toString() }
|
||||
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v }
|
||||
final override Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
final override IR::Instruction asInstruction() { result = instr }
|
||||
}
|
||||
|
||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||
IR::Operand op;
|
||||
|
||||
SsaOperand() { this = TSsaOperand(op) }
|
||||
|
||||
final override string toString() { result = op.toString() }
|
||||
|
||||
final override Location getLocation() { result = op.getLocation() }
|
||||
|
||||
final override IR::Operand asOperand() { result = op }
|
||||
}
|
||||
|
||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v.asInstruction() = sourceExpr }
|
||||
|
||||
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
|
||||
|
||||
SsaVariable getAPhiInput(SsaVariable v) {
|
||||
exists(IR::PhiInstruction instr |
|
||||
result.asInstruction() = instr.getAnInput()
|
||||
or
|
||||
result.asOperand() = instr.getAnInputOperand()
|
||||
)
|
||||
}
|
||||
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
result = getSemanticType(v.(IR::Instruction).getResultIRType())
|
||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||
}
|
||||
|
||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) { result = v.(IR::Instruction).getBlock() }
|
||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
||||
result = v.asInstruction().getBlock()
|
||||
or
|
||||
result = v.asOperand().getUse().getBlock()
|
||||
}
|
||||
|
||||
private newtype TReadPosition =
|
||||
TReadPositionBlock(IR::IRBlock block) or
|
||||
@@ -169,7 +209,9 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::Operand operand |
|
||||
operand.getDef() = v and not operand instanceof IR::PhiInputOperand
|
||||
operand.getDef() = v.asInstruction() and
|
||||
not operand instanceof IR::PhiInputOperand and
|
||||
operand.getUse().getBlock() = block
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -186,7 +228,7 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
operand.getDef() = v and
|
||||
operand.getDef() = v.asInstruction() and
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
)
|
||||
@@ -205,17 +247,16 @@ module SemanticExprConfig {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
||||
|
|
||||
phi = operand.getUse() and input = operand.getDef()
|
||||
phi.asInstruction() = operand.getUse() and
|
||||
(
|
||||
input.asInstruction() = operand.getDef()
|
||||
or
|
||||
input.asOperand() = operand
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class Bound instanceof IRBound::Bound {
|
||||
Bound() {
|
||||
this instanceof IRBound::ZeroBound
|
||||
or
|
||||
this.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction() instanceof SsaVariable
|
||||
}
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
final Location getLocation() { result = super.getLocation() }
|
||||
@@ -228,13 +269,13 @@ module SemanticExprConfig {
|
||||
|
||||
override string toString() {
|
||||
result =
|
||||
min(SsaVariable instr |
|
||||
instr = bound.getValueNumber().getAnInstruction()
|
||||
min(SsaVariable v |
|
||||
v.asInstruction() = bound.getValueNumber().getAnInstruction()
|
||||
|
|
||||
instr
|
||||
v
|
||||
order by
|
||||
instr.(IR::Instruction).getBlock().getDisplayIndex(),
|
||||
instr.(IR::Instruction).getDisplayIndexInBlock()
|
||||
v.asInstruction().getBlock().getDisplayIndex(),
|
||||
v.asInstruction().getDisplayIndexInBlock()
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
@@ -242,7 +283,7 @@ module SemanticExprConfig {
|
||||
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
|
||||
|
||||
predicate ssaBound(Bound bound, SsaVariable v) {
|
||||
v = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
|
||||
v.asInstruction() = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
|
||||
}
|
||||
|
||||
Expr getBoundExpr(Bound bound, int delta) {
|
||||
@@ -251,22 +292,20 @@ module SemanticExprConfig {
|
||||
|
||||
class Guard = IRGuards::IRGuardCondition;
|
||||
|
||||
predicate guard(Guard guard, BasicBlock block) {
|
||||
block = guard.(IRGuards::IRGuardCondition).getBlock()
|
||||
}
|
||||
predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
|
||||
|
||||
Expr getGuardAsExpr(Guard guard) { result = guard }
|
||||
|
||||
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
|
||||
guard.(IRGuards::IRGuardCondition).comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||
guard.comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controls(controlled, branch)
|
||||
guard.controls(controlled, branch)
|
||||
}
|
||||
|
||||
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controlsEdge(bb1, bb2, branch)
|
||||
guard.controlsEdge(bb1, bb2, branch)
|
||||
}
|
||||
|
||||
Guard comparisonGuard(Expr e) { result = e }
|
||||
@@ -284,9 +323,13 @@ SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
|
||||
|
||||
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result }
|
||||
|
||||
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) { result = instr }
|
||||
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) {
|
||||
result.(SemanticExprConfig::SsaVariable).asInstruction() = instr
|
||||
}
|
||||
|
||||
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable v) { v = result }
|
||||
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable var) {
|
||||
var.(SemanticExprConfig::SsaVariable).asInstruction() = result
|
||||
}
|
||||
|
||||
SemBound getSemanticBound(IRBound::Bound bound) { result = bound }
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod
|
||||
/**
|
||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
|
||||
rix = 0 and
|
||||
phiModulusInit(phi, b, val, mod)
|
||||
@@ -169,7 +170,7 @@ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int
|
||||
val = remainder(v1, mod)
|
||||
|
|
||||
exists(int v2, int m2 |
|
||||
rankedPhiInput(phi, inp, edge, rix) and
|
||||
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
ssaModulus(inp, edge, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2)
|
||||
|
||||
@@ -342,7 +342,10 @@ private class ConvertOrBoxExpr extends SemUnaryExpr {
|
||||
* A cast that can be ignored for the purpose of range analysis.
|
||||
*/
|
||||
private class SafeCastExpr extends ConvertOrBoxExpr {
|
||||
SafeCastExpr() { conversionCannotOverflow(getTrackedType(getOperand()), getTrackedType(this)) }
|
||||
SafeCastExpr() {
|
||||
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
|
||||
getTrackedType(this))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -189,9 +189,12 @@ private class BinarySignExpr extends FlowSignExpr {
|
||||
BinarySignExpr() { binary = this }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result =
|
||||
semExprSign(binary.getLeftOperand())
|
||||
.applyBinaryOp(semExprSign(binary.getRightOperand()), binary.getOpcode())
|
||||
exists(SemExpr left, SemExpr right |
|
||||
binaryExprOperands(binary, left, right) and
|
||||
result =
|
||||
semExprSign(pragma[only_bind_out](left))
|
||||
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
|
||||
)
|
||||
or
|
||||
exists(SemDivExpr div | div = binary |
|
||||
result = semExprSign(div.getLeftOperand()) and
|
||||
@@ -201,6 +204,10 @@ private class BinarySignExpr extends FlowSignExpr {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
|
||||
binary.getLeftOperand() = left and binary.getRightOperand() = right
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression.
|
||||
*/
|
||||
@@ -221,7 +228,7 @@ private class UnarySignExpr extends FlowSignExpr {
|
||||
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = semExprSign(unary.getOperand()).applyUnaryOp(unary.getOpcode())
|
||||
result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ private module Liveness {
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
||||
*/
|
||||
private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
||||
or
|
||||
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
||||
@@ -76,6 +76,10 @@ private module Liveness {
|
||||
not result + 1 = refRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
|
||||
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
||||
* that is either a read or a certain write.
|
||||
@@ -185,23 +189,29 @@ newtype TDefinition =
|
||||
|
||||
private module SsaDefReaches {
|
||||
newtype TSsaRefKind =
|
||||
SsaRead() or
|
||||
SsaActualRead() or
|
||||
SsaPhiRead() or
|
||||
SsaDef()
|
||||
|
||||
class SsaRead = SsaActualRead or SsaPhiRead;
|
||||
|
||||
/**
|
||||
* A classification of SSA variable references into reads and definitions.
|
||||
*/
|
||||
class SsaRefKind extends TSsaRefKind {
|
||||
string toString() {
|
||||
this = SsaRead() and
|
||||
result = "SsaRead"
|
||||
this = SsaActualRead() and
|
||||
result = "SsaActualRead"
|
||||
or
|
||||
this = SsaPhiRead() and
|
||||
result = "SsaPhiRead"
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = "SsaDef"
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this = SsaRead() and
|
||||
this instanceof SsaRead and
|
||||
result = 0
|
||||
or
|
||||
this = SsaDef() and
|
||||
@@ -209,6 +219,80 @@ private module SsaDefReaches {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* read of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||
lastRefIsRead(readbb, v)
|
||||
or
|
||||
phiRead(readbb, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a phi-read node should be inserted for variable `v` at the beginning
|
||||
* of basic block `bb`.
|
||||
*
|
||||
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
|
||||
* instead of writes, and only if the dominance-frontier block does not already
|
||||
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
|
||||
* an internal implementation detail that is not exposed.
|
||||
*
|
||||
* The motivation for adding phi-reads is to improve performance of the use-use
|
||||
* calculation in cases where there is a large number of reads that can reach the
|
||||
* same join-point, and from there reach a large number of basic blocks. Example:
|
||||
*
|
||||
* ```cs
|
||||
* if (a)
|
||||
* use(x);
|
||||
* else if (b)
|
||||
* use(x);
|
||||
* else if (c)
|
||||
* use(x);
|
||||
* else if (d)
|
||||
* use(x);
|
||||
* // many more ifs ...
|
||||
*
|
||||
* // phi-read for `x` inserted here
|
||||
*
|
||||
* // program not mentioning `x`, with large basic block graph
|
||||
*
|
||||
* use(x);
|
||||
* ```
|
||||
*
|
||||
* Without phi-reads, the analysis has to replicate reachability for each of
|
||||
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
|
||||
* each conditional use of `x` to reach the basic block containing the phi-read
|
||||
* node for `x`, and only that basic block will have to compute reachability
|
||||
* through the remainder of the large program.
|
||||
*
|
||||
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
|
||||
* one SSA definition (without passing through another definition): Assume, for
|
||||
* the sake of contradiction, that there are two reaching definitions `def1` and
|
||||
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
|
||||
* dominating definition will prevent the other from reaching `phi-read`. So, at
|
||||
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
|
||||
* Then `def1` must go through one of its dominance-frontier blocks in order to
|
||||
* reach `phi-read`. However, such a block will always start with a (normal) phi
|
||||
* node, which contradicts reachability.
|
||||
*
|
||||
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
|
||||
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
|
||||
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
|
||||
* which contradicts reachability.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiRead(BasicBlock bb, SourceVariable v) {
|
||||
inReadDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v) and
|
||||
// only if there are no other references to `v` inside `bb`
|
||||
not ref(bb, _, v, _) and
|
||||
not exists(Definition def | def.definesAt(v, bb, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
||||
@@ -216,11 +300,16 @@ private module SsaDefReaches {
|
||||
*
|
||||
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
variableRead(bb, i, v, _) and
|
||||
k = SsaRead()
|
||||
k = SsaActualRead()
|
||||
or
|
||||
exists(Definition def | def.definesAt(v, bb, i)) and
|
||||
phiRead(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaPhiRead()
|
||||
or
|
||||
any(Definition def).definesAt(v, bb, i) and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
@@ -273,7 +362,7 @@ private module SsaDefReaches {
|
||||
)
|
||||
or
|
||||
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
||||
rnk = ssaRefRank(bb, _, v, SsaRead())
|
||||
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,7 +372,7 @@ private module SsaDefReaches {
|
||||
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
exists(int rnk |
|
||||
ssaDefReachesRank(bb, def, rnk, v) and
|
||||
rnk = ssaRefRank(bb, i, v, SsaRead())
|
||||
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -309,45 +398,94 @@ private module SsaDefReaches {
|
||||
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
||||
}
|
||||
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
|
||||
exists(ssaDefRank(def, v, bb, _, _))
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
|
||||
exists(ssaDefRank(def, v, bb, _, k))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
||||
ssaDefReachesEndOfBlock(bb, def, _) and
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable())
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`,
|
||||
* and the underlying variable for `def` is neither read nor written in any block
|
||||
* on the path between `bb1` and `bb2`.
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
|
||||
* predecessor of `bb2`, and the underlying variable for `def` is neither read
|
||||
* nor written in any block on the path between `bb1` and `bb2`.
|
||||
*
|
||||
* Phi reads are considered as normal reads for this predicate.
|
||||
*/
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _) and
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _, _) and
|
||||
bb2 = getABasicBlockSuccessor(bb1)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReaches(def, bb1, mid) and
|
||||
varBlockReachesInclPhiRead(def, bb1, mid) and
|
||||
ssaDefReachesThroughBlock(def, mid) and
|
||||
bb2 = getABasicBlockSuccessor(mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(def, bb1, bb2) and
|
||||
defOccursInBlock(def, bb2, v, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
|
||||
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExclPhiRead(def, mid, bb2) and
|
||||
phiReadStep(def, _, bb1, mid)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive
|
||||
* successor block of `bb1`, and `def` is neither read nor written in any block
|
||||
* on a path between `bb1` and `bb2`.
|
||||
* the underlying variable `v` of `def` is accessed in basic block `bb2`
|
||||
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
|
||||
* `v` is neither read nor written in any block on the path between `bb1`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesExclPhiRead(def, bb1, bb2) and
|
||||
not defOccursInBlock(def, bb1, _, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
||||
varBlockReaches(def, bb1, bb2) and
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
|
||||
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
|
||||
* and `v` is neither read nor written in any block on the path between `bb`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
|
||||
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExit(def, mid) and
|
||||
phiReadStep(def, _, bb, mid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate phiReadExposedForTesting = phiRead/2;
|
||||
|
||||
private import SsaDefReaches
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -365,7 +503,8 @@ predicate liveThrough(BasicBlock bb, SourceVariable v) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
||||
exists(int last | last = maxSsaRefRank(bb, v) |
|
||||
exists(int last |
|
||||
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
|
||||
ssaDefReachesRank(bb, def, last, v) and
|
||||
liveAtExit(bb, v)
|
||||
)
|
||||
@@ -405,7 +544,7 @@ pragma[nomagic]
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||
or
|
||||
variableRead(bb, i, v, _) and
|
||||
ssaRef(bb, i, v, any(SsaRead k)) and
|
||||
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||
}
|
||||
@@ -421,7 +560,7 @@ pragma[nomagic]
|
||||
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
exists(int rnk |
|
||||
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
|
||||
variableRead(bb1, i2, _, _) and
|
||||
bb2 = bb1
|
||||
)
|
||||
@@ -538,18 +677,15 @@ predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Def
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
||||
// Can reach another definition
|
||||
lastRefRedef(def, bb, i, _)
|
||||
or
|
||||
lastSsaRef(def, _, bb, i) and
|
||||
(
|
||||
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
|
||||
// Can reach exit directly
|
||||
bb instanceof ExitBasicBlock
|
||||
or
|
||||
// Can reach a block using one or more steps, where `def` is no longer live
|
||||
exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
varBlockReachesExit(def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
||||
abstract Language::Location getLocation();
|
||||
}
|
||||
|
||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
private IRFunction irFunc;
|
||||
|
||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
||||
result =
|
||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||
}
|
||||
|
||||
IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
|
||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
||||
abstract Language::Location getLocation();
|
||||
}
|
||||
|
||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
private IRFunction irFunc;
|
||||
|
||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
||||
result =
|
||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||
}
|
||||
|
||||
IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
|
||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
||||
abstract Language::Location getLocation();
|
||||
}
|
||||
|
||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
private IRFunction irFunc;
|
||||
|
||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
||||
result =
|
||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||
}
|
||||
|
||||
IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
|
||||
@@ -11,12 +11,6 @@ private class StdPair extends ClassTemplateInstantiation {
|
||||
StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: This is now called `StdPair` and is a private part of the
|
||||
* library implementation.
|
||||
*/
|
||||
deprecated class StdPairClass = StdPair;
|
||||
|
||||
/**
|
||||
* Any of the single-parameter constructors of `std::pair` that takes a reference to an
|
||||
* instantiation of `std::pair`. These constructors allow conversion between pair types when the
|
||||
|
||||
@@ -27,13 +27,6 @@ abstract class RemoteFlowSourceFunction extends Function {
|
||||
predicate hasSocketInput(FunctionInput input) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RemoteFlowSourceFunction` instead.
|
||||
*
|
||||
* A library function that returns data that may be read from a network connection.
|
||||
*/
|
||||
deprecated class RemoteFlowFunction = RemoteFlowSourceFunction;
|
||||
|
||||
/**
|
||||
* A library function that returns data that is directly controlled by a user.
|
||||
*/
|
||||
@@ -44,13 +37,6 @@ abstract class LocalFlowSourceFunction extends Function {
|
||||
abstract predicate hasLocalFlowSource(FunctionOutput output, string description);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `LocalFlowSourceFunction` instead.
|
||||
*
|
||||
* A library function that returns data that is directly controlled by a user.
|
||||
*/
|
||||
deprecated class LocalFlowFunction = LocalFlowSourceFunction;
|
||||
|
||||
/** A library function that sends data over a network connection. */
|
||||
abstract class RemoteFlowSinkFunction extends Function {
|
||||
/**
|
||||
|
||||
@@ -290,7 +290,11 @@ class PathElement extends TPathElement {
|
||||
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
|
||||
|
||||
string toString() {
|
||||
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
|
||||
result =
|
||||
[
|
||||
this.asStore().toString(), this.asCall(_).toString(), this.asMid().toString(),
|
||||
this.asSink(_).toString()
|
||||
]
|
||||
}
|
||||
|
||||
predicate hasLocationInfo(
|
||||
|
||||
@@ -30,7 +30,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
|
||||
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
|
||||
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,12 @@ import cpp
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency as IRConsistency
|
||||
|
||||
class PresentIRFunction extends IRConsistency::PresentIRFunction {
|
||||
override string toString() {
|
||||
result = min(string name | name = this.getIRFunction().getFunction().getQualifiedName() | name)
|
||||
}
|
||||
}
|
||||
|
||||
select count(Instruction i | IRConsistency::missingOperand(i, _, _, _) | i) as missingOperand,
|
||||
count(Instruction i | IRConsistency::unexpectedOperand(i, _, _, _) | i) as unexpectedOperand,
|
||||
count(Instruction i | IRConsistency::duplicateOperand(i, _, _, _) | i) as duplicateOperand,
|
||||
|
||||
@@ -67,7 +67,7 @@ predicate findUseCharacterConversion(Expr exp, string msg) {
|
||||
exists(FunctionCall fc |
|
||||
fc = exp and
|
||||
(
|
||||
exists(Loop lptmp | lptmp = fc.getEnclosingStmt().getParentStmt*()) and
|
||||
fc.getEnclosingStmt().getParentStmt*() instanceof Loop and
|
||||
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
|
||||
not fc.getArgument(0).isConstant() and
|
||||
not fc.getArgument(1).isConstant() and
|
||||
|
||||
@@ -44,11 +44,8 @@ predicate conversionDoneLate(MulExpr mexp) {
|
||||
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
|
||||
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
|
||||
or
|
||||
e0.(FunctionCall)
|
||||
.getTarget()
|
||||
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
|
||||
.getType()
|
||||
.getSize() = mexp.getConversion().getConversion().getType().getSize()
|
||||
e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
|
||||
mexp.getConversion().getConversion().getType().getSize()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -75,7 +72,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
|
||||
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
|
||||
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
|
||||
(
|
||||
not exists(DivExpr de | mexp.getParent*() = de)
|
||||
not mexp.getParent*() instanceof DivExpr
|
||||
or
|
||||
exists(DivExpr de, Expr ec |
|
||||
e2.isConstant() and
|
||||
|
||||
@@ -33,7 +33,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
|
||||
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
|
||||
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
@@ -37,8 +38,13 @@ private string getBoundString(SemBound b, int delta) {
|
||||
b instanceof SemZeroBound and result = delta.toString()
|
||||
or
|
||||
result =
|
||||
strictconcat(b.(SemSsaBound).getAVariable().(IR::Instruction).getAst().toString(), ":") +
|
||||
getOffsetString(delta)
|
||||
strictconcat(b.(SemSsaBound)
|
||||
.getAVariable()
|
||||
.(SemanticExprConfig::SsaVariable)
|
||||
.asInstruction()
|
||||
.getAst()
|
||||
.toString(), ":"
|
||||
) + getOffsetString(delta)
|
||||
}
|
||||
|
||||
private string getARangeString(SemExpr e) {
|
||||
|
||||
Reference in New Issue
Block a user