Merge branch 'master' into getPhiOperandDefinition-perf-2

This commit is contained in:
Robert Marsh
2020-01-16 07:23:59 -08:00
259 changed files with 28243 additions and 11231 deletions

View File

@@ -18,6 +18,8 @@
import cpp
import semmle.code.cpp.controlflow.SSA
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
/**
* Holds if `e` is either:
@@ -64,6 +66,110 @@ int getEffectiveMulOperands(MulExpr me) {
)
}
/**
* As SimpleRangeAnalysis does not support reasoning about multiplication
* we create a tiny abstract interpreter for handling multiplication, which
* we invoke only after weeding out of all of trivial cases that we do
* not care about. By default, the maximum and minimum values are computed
* using SimpleRangeAnalysis.
*/
class AnalyzableExpr extends Expr {
float maxValue() { result = upperBound(this.getFullyConverted()) }
float minValue() { result = lowerBound(this.getFullyConverted()) }
}
class ParenAnalyzableExpr extends AnalyzableExpr, ParenthesisExpr {
override float maxValue() { result = this.getExpr().(AnalyzableExpr).maxValue() }
override float minValue() { result = this.getExpr().(AnalyzableExpr).minValue() }
}
class MulAnalyzableExpr extends AnalyzableExpr, MulExpr {
override float maxValue() {
exists(float x1, float y1, float x2, float y2 |
x1 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() and
x2 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
y1 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() and
y2 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
result = (x1 * y1).maximum(x1 * y2).maximum(x2 * y1).maximum(x2 * y2)
)
}
override float minValue() {
exists(float x1, float x2, float y1, float y2 |
x1 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() and
x2 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
y1 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() and
y2 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
result = (x1 * y1).minimum(x1 * y2).minimum(x2 * y1).minimum(x2 * y2)
)
}
}
class AddAnalyzableExpr extends AnalyzableExpr, AddExpr {
override float maxValue() {
result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() +
this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue()
}
override float minValue() {
result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() +
this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue()
}
}
class SubAnalyzableExpr extends AnalyzableExpr, SubExpr {
override float maxValue() {
result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() -
this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue()
}
override float minValue() {
result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() -
this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue()
}
}
class VarAnalyzableExpr extends AnalyzableExpr, VariableAccess {
VarAnalyzableExpr() { this.getTarget() instanceof StackVariable }
override float maxValue() {
exists(SsaDefinition def, Variable v |
def.getAUse(v) = this and
// if there is a defining expression, use that for
// computing the maximum value. Otherwise, assign the
// variable the largest possible value it can hold
if exists(def.getDefiningValue(v))
then result = def.getDefiningValue(v).(AnalyzableExpr).maxValue()
else result = upperBound(this)
)
}
override float minValue() {
exists(SsaDefinition def, Variable v |
def.getAUse(v) = this and
if exists(def.getDefiningValue(v))
then result = def.getDefiningValue(v).(AnalyzableExpr).minValue()
else result = lowerBound(this)
)
}
}
/**
* Holds if `t` is not an instance of `IntegralType`,
* or if `me` cannot be proven to not overflow
*/
predicate overflows(MulExpr me, Type t) {
t instanceof IntegralType
implies
(
me.(MulAnalyzableExpr).maxValue() > exprMaxVal(me)
or
me.(MulAnalyzableExpr).minValue() < exprMinVal(me)
)
}
from MulExpr me, Type t1, Type t2
where
t1 = me.getType().getUnderlyingType() and
@@ -101,7 +207,11 @@ where
e = other.(BinaryOperation).getAnOperand*()
) and
e.(Literal).getType().getSize() = t2.getSize()
)
) and
// only report if we cannot prove that the result of the
// multiplication will be less (resp. greater) than the
// maximum (resp. minimum) number we can compute.
overflows(me, t1)
select me,
"Multiplication result may overflow '" + me.getType().toString() + "' before it is converted to '"
+ me.getFullyConverted().getType().toString() + "'."

View File

@@ -25,10 +25,16 @@ predicate assertInvocation(File f, int line) {
)
}
predicate nullCheckAssert(Expr e, Variable v, Declaration qualifier) {
nullCheckInCondition(e, v, qualifier) and
class InterestingExpr extends Expr {
InterestingExpr() { nullCheckInCondition(this, _, _) }
}
predicate nullCheckAssert(InterestingExpr e, Variable v, Declaration qualifier) {
exists(File f, int i |
e.getLocation().getStartLine() = i and e.getFile() = f and assertInvocation(f, i)
e.getLocation().getStartLine() = i and
e.getFile() = f and
assertInvocation(f, i) and
nullCheckInCondition(e, v, qualifier)
)
}

View File

@@ -38,6 +38,12 @@ abstract class BooleanControllingAssignment extends AssignExpr {
abstract predicate isWhitelisted();
}
/**
* Gets an operand of a logical operation expression (we need the restriction
* to BinaryLogicalOperation expressions to get the correct transitive closure).
*/
Expr getComparisonOperand(BinaryLogicalOperation op) { result = op.getAnOperand() }
class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
BooleanControllingAssignmentInExpr() {
this.getParent() instanceof UnaryLogicalOperation or
@@ -45,7 +51,18 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
exists(ConditionalExpr c | c.getCondition() = this)
}
override predicate isWhitelisted() { this.getConversion().(ParenthesisExpr).isParenthesised() }
override predicate isWhitelisted() {
this.getConversion().(ParenthesisExpr).isParenthesised()
or
// whitelist this assignment if all comparison operations in the expression that this
// assignment is part of, are not parenthesized. In that case it seems like programmer
// is fine with unparenthesized comparison operands to binary logical operators, and
// the parenthesis around this assignment was used to call it out as an assignment.
this.isParenthesised() and
forex(ComparisonOperation op | op = getComparisonOperand*(this.getParent+()) |
not op.isParenthesised()
)
}
}
class BooleanControllingAssignmentInStmt extends BooleanControllingAssignment {
@@ -65,7 +82,8 @@ class BooleanControllingAssignmentInStmt extends BooleanControllingAssignment {
*/
predicate candidateResult(BooleanControllingAssignment ae) {
ae.getRValue().isConstant() and
not ae.isWhitelisted()
not ae.isWhitelisted() and
not ae.getRValue() instanceof StringLiteral
}
/**
@@ -81,5 +99,6 @@ predicate candidateVariable(Variable v) {
from BooleanControllingAssignment ae, UndefReachability undef
where
candidateResult(ae) and
not ae.isFromUninstantiatedTemplate(_) and
not undef.reaches(_, ae.getLValue().(VariableAccess).getTarget(), ae.getLValue())
select ae, "Use of '=' where '==' may have been intended."

View File

@@ -16,12 +16,19 @@ import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTracking
predicate isRandCall(FunctionCall fc) { fc.getTarget().getName() = "rand" }
predicate isRandCallOrParent(Expr e) {
isRandCall(e) or
isRandCallOrParent(e.getAChild())
}
predicate isRandValue(Expr e) {
e.(FunctionCall).getTarget().getName() = "rand"
isRandCall(e)
or
exists(MacroInvocation mi |
e = mi.getExpr() and
e.getAChild*().(FunctionCall).getTarget().getName() = "rand"
isRandCallOrParent(e)
)
}

View File

@@ -93,6 +93,10 @@ predicate assignOperatorWithWrongResult(Operator op, string msg) {
from Operator op, string msg
where
assignOperatorWithWrongType(op, msg) or
assignOperatorWithWrongResult(op, msg)
(
assignOperatorWithWrongType(op, msg) or
assignOperatorWithWrongResult(op, msg)
) and
// exclude code in templates which may be incomplete
not op.isFromUninstantiatedTemplate(_)
select op, msg

View File

@@ -46,6 +46,10 @@ predicate functionImperfectlyExtracted(Function f) {
exists(ErrorExpr ee | ee.getEnclosingFunction() = f)
or
count(f.getType()) > 1
or
// an `AsmStmt` isn't strictly 'imperfectly extracted', but it's beyond the scope
// of this analysis.
exists(AsmStmt asm | asm.getEnclosingFunction() = f)
}
from Stmt stmt, string msg, Function f, ControlFlowNode blame

File diff suppressed because it is too large Load Diff

View File

@@ -112,9 +112,6 @@ private module ImplCommon {
enclosing = arg.getEnclosingCallable()
}
pragma[noinline]
private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c }
pragma[noinline]
private predicate viableParamArg0(
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
@@ -123,9 +120,9 @@ private module ImplCommon {
(
outercc = TAnyCallContext()
or
outercc = TSomeCall(getAParameter(c), _)
outercc = TSomeCall()
or
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
exists(DataFlowCall other | outercc = TSpecificCall(other) |
recordDataFlowCallSite(other, c)
)
) and
@@ -156,17 +153,17 @@ private module ImplCommon {
viableParamArg1(p, callable, i, arg, outercc, call)
|
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, true)
else innercc = TSomeCall(p, true)
then innercc = TSpecificCall(call)
else innercc = TSomeCall()
)
}
private CallContextCall getAValidCallContextForParameter(ParameterNode p) {
result = TSomeCall(p, _)
result = TSomeCall()
or
exists(DataFlowCall call, int i, DataFlowCallable callable |
result = TSpecificCall(call, i, _) and
p.isParameterOf(callable, i) and
exists(DataFlowCall call, DataFlowCallable callable |
result = TSpecificCall(call) and
p.isParameterOf(callable, _) and
recordDataFlowCallSite(call, callable)
)
}
@@ -460,9 +457,6 @@ private module ImplCommon {
enclosing = arg.getEnclosingCallable()
}
pragma[noinline]
private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c }
pragma[noinline]
private predicate viableParamArg0(
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
@@ -471,9 +465,9 @@ private module ImplCommon {
(
outercc = TAnyCallContext()
or
outercc = TSomeCall(getAParameter(c), _)
outercc = TSomeCall()
or
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
exists(DataFlowCall other | outercc = TSpecificCall(other) |
recordDataFlowCallSite(other, c)
)
) and
@@ -504,17 +498,17 @@ private module ImplCommon {
viableParamArg1(p, callable, i, arg, outercc, call)
|
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, true)
else innercc = TSomeCall(p, true)
then innercc = TSpecificCall(call)
else innercc = TSomeCall()
)
}
private CallContextCall getAValidCallContextForParameter(ParameterNode p) {
result = TSomeCall(p, _)
result = TSomeCall()
or
exists(DataFlowCall call, int i, DataFlowCallable callable |
result = TSpecificCall(call, i, _) and
p.isParameterOf(callable, i) and
exists(DataFlowCall call, DataFlowCallable callable |
result = TSpecificCall(call) and
p.isParameterOf(callable, _) and
recordDataFlowCallSite(call, callable)
)
}
@@ -579,14 +573,6 @@ private module ImplCommon {
}
}
/**
* Holds if `call` passes an implicit or explicit instance argument, i.e., an
* expression that reaches a `this` parameter.
*/
private predicate callHasInstanceArgument(DataFlowCall call) {
exists(ArgumentNode arg | arg.argumentOf(call, -1))
}
/**
* Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -601,16 +587,8 @@ private module ImplCommon {
cached
newtype TCallContext =
TAnyCallContext() or
TSpecificCall(DataFlowCall call, int i, boolean emptyAp) {
recordDataFlowCallSite(call, _) and
(emptyAp = true or emptyAp = false) and
(
exists(call.getArgument(i))
or
i = -1 and callHasInstanceArgument(call)
)
} or
TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or
TSpecificCall(DataFlowCall call) { recordDataFlowCallSite(call, _) } or
TSomeCall() or
TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) }
cached
@@ -635,11 +613,11 @@ private module ImplCommon {
*
* There are four cases:
* - `TAnyCallContext()` : No restrictions on method flow.
* - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th
* parameter at the given `call`. This call improves the set of viable
* - `TSpecificCall(DataFlowCall call)` : Flow entered through the
* given `call`. This call improves the set of viable
* dispatch targets for at least one method call in the current callable
* or helps prune unreachable nodes in the current callable.
* - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The
* - `TSomeCall()` : Flow entered through a parameter. The
* originating call does not improve the set of dispatch targets for any
* method call in the current callable and was therefore not recorded.
* - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and
@@ -663,23 +641,21 @@ private module ImplCommon {
class CallContextSpecificCall extends CallContextCall, TSpecificCall {
override string toString() {
exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) |
result = "CcCall(" + call + ", " + i + ")"
)
exists(DataFlowCall call | this = TSpecificCall(call) | result = "CcCall(" + call + ")")
}
override predicate relevantFor(DataFlowCallable callable) {
recordDataFlowCallSite(getCall(), callable)
}
DataFlowCall getCall() { this = TSpecificCall(result, _, _) }
DataFlowCall getCall() { this = TSpecificCall(result) }
}
class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | this = TSomeCall(p, _) and p.getEnclosingCallable() = callable)
exists(ParameterNode p | p.getEnclosingCallable() = callable)
}
}
@@ -848,7 +824,7 @@ private module ImplCommon {
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) |
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
if reducedViableImplInCallContext(call, _, ctx)
then result = prunedViableImplInCallContext(call, ctx)
else result = viableCallable(call)
@@ -861,6 +837,76 @@ private module ImplCommon {
result = viableCallable(call) and cc instanceof CallContextReturn
}
newtype TSummary =
TSummaryVal() or
TSummaryTaint() or
TSummaryReadVal(Content f) or
TSummaryReadTaint(Content f) or
TSummaryTaintStore(Content f)
/**
* A summary of flow through a callable. This can either be value-preserving
* if no additional steps are used, taint-flow if at least one additional step
* is used, or any one of those combined with a store or a read. Summaries
* recorded at a return node are restricted to include at least one additional
* step, as the value-based summaries are calculated independent of the
* configuration.
*/
class Summary extends TSummary {
string toString() {
result = "Val" and this = TSummaryVal()
or
result = "Taint" and this = TSummaryTaint()
or
exists(Content f |
result = "ReadVal " + f.toString() and this = TSummaryReadVal(f)
or
result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f)
or
result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f)
)
}
/** Gets the summary that results from extending this with an additional step. */
Summary additionalStep() {
this = TSummaryVal() and result = TSummaryTaint()
or
this = TSummaryTaint() and result = TSummaryTaint()
or
exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f))
or
exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f))
}
/** Gets the summary that results from extending this with a read. */
Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) }
/** Gets the summary that results from extending this with a store. */
Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) }
/** Gets the summary that results from extending this with `step`. */
bindingset[this, step]
Summary compose(Summary step) {
this = TSummaryVal() and result = step
or
this = TSummaryTaint() and
(step = TSummaryTaint() or step = TSummaryTaintStore(_)) and
result = step
or
exists(Content f |
this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f)
)
or
this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this
}
/** Holds if this summary does not include any taint steps. */
predicate isPartial() {
this = TSummaryVal() or
this = TSummaryReadVal(_)
}
}
pragma[noinline]
DataFlowType getErasedNodeType(Node n) { result = getErasedRepr(n.getType()) }

View File

@@ -112,9 +112,6 @@ private module ImplCommon {
enclosing = arg.getEnclosingCallable()
}
pragma[noinline]
private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c }
pragma[noinline]
private predicate viableParamArg0(
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
@@ -123,9 +120,9 @@ private module ImplCommon {
(
outercc = TAnyCallContext()
or
outercc = TSomeCall(getAParameter(c), _)
outercc = TSomeCall()
or
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
exists(DataFlowCall other | outercc = TSpecificCall(other) |
recordDataFlowCallSite(other, c)
)
) and
@@ -156,17 +153,17 @@ private module ImplCommon {
viableParamArg1(p, callable, i, arg, outercc, call)
|
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, true)
else innercc = TSomeCall(p, true)
then innercc = TSpecificCall(call)
else innercc = TSomeCall()
)
}
private CallContextCall getAValidCallContextForParameter(ParameterNode p) {
result = TSomeCall(p, _)
result = TSomeCall()
or
exists(DataFlowCall call, int i, DataFlowCallable callable |
result = TSpecificCall(call, i, _) and
p.isParameterOf(callable, i) and
exists(DataFlowCall call, DataFlowCallable callable |
result = TSpecificCall(call) and
p.isParameterOf(callable, _) and
recordDataFlowCallSite(call, callable)
)
}
@@ -460,9 +457,6 @@ private module ImplCommon {
enclosing = arg.getEnclosingCallable()
}
pragma[noinline]
private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c }
pragma[noinline]
private predicate viableParamArg0(
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
@@ -471,9 +465,9 @@ private module ImplCommon {
(
outercc = TAnyCallContext()
or
outercc = TSomeCall(getAParameter(c), _)
outercc = TSomeCall()
or
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
exists(DataFlowCall other | outercc = TSpecificCall(other) |
recordDataFlowCallSite(other, c)
)
) and
@@ -504,17 +498,17 @@ private module ImplCommon {
viableParamArg1(p, callable, i, arg, outercc, call)
|
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, true)
else innercc = TSomeCall(p, true)
then innercc = TSpecificCall(call)
else innercc = TSomeCall()
)
}
private CallContextCall getAValidCallContextForParameter(ParameterNode p) {
result = TSomeCall(p, _)
result = TSomeCall()
or
exists(DataFlowCall call, int i, DataFlowCallable callable |
result = TSpecificCall(call, i, _) and
p.isParameterOf(callable, i) and
exists(DataFlowCall call, DataFlowCallable callable |
result = TSpecificCall(call) and
p.isParameterOf(callable, _) and
recordDataFlowCallSite(call, callable)
)
}
@@ -579,14 +573,6 @@ private module ImplCommon {
}
}
/**
* Holds if `call` passes an implicit or explicit instance argument, i.e., an
* expression that reaches a `this` parameter.
*/
private predicate callHasInstanceArgument(DataFlowCall call) {
exists(ArgumentNode arg | arg.argumentOf(call, -1))
}
/**
* Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -601,16 +587,8 @@ private module ImplCommon {
cached
newtype TCallContext =
TAnyCallContext() or
TSpecificCall(DataFlowCall call, int i, boolean emptyAp) {
recordDataFlowCallSite(call, _) and
(emptyAp = true or emptyAp = false) and
(
exists(call.getArgument(i))
or
i = -1 and callHasInstanceArgument(call)
)
} or
TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or
TSpecificCall(DataFlowCall call) { recordDataFlowCallSite(call, _) } or
TSomeCall() or
TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) }
cached
@@ -635,11 +613,11 @@ private module ImplCommon {
*
* There are four cases:
* - `TAnyCallContext()` : No restrictions on method flow.
* - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th
* parameter at the given `call`. This call improves the set of viable
* - `TSpecificCall(DataFlowCall call)` : Flow entered through the
* given `call`. This call improves the set of viable
* dispatch targets for at least one method call in the current callable
* or helps prune unreachable nodes in the current callable.
* - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The
* - `TSomeCall()` : Flow entered through a parameter. The
* originating call does not improve the set of dispatch targets for any
* method call in the current callable and was therefore not recorded.
* - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and
@@ -663,23 +641,21 @@ private module ImplCommon {
class CallContextSpecificCall extends CallContextCall, TSpecificCall {
override string toString() {
exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) |
result = "CcCall(" + call + ", " + i + ")"
)
exists(DataFlowCall call | this = TSpecificCall(call) | result = "CcCall(" + call + ")")
}
override predicate relevantFor(DataFlowCallable callable) {
recordDataFlowCallSite(getCall(), callable)
}
DataFlowCall getCall() { this = TSpecificCall(result, _, _) }
DataFlowCall getCall() { this = TSpecificCall(result) }
}
class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | this = TSomeCall(p, _) and p.getEnclosingCallable() = callable)
exists(ParameterNode p | p.getEnclosingCallable() = callable)
}
}
@@ -848,7 +824,7 @@ private module ImplCommon {
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) |
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
if reducedViableImplInCallContext(call, _, ctx)
then result = prunedViableImplInCallContext(call, ctx)
else result = viableCallable(call)
@@ -861,6 +837,76 @@ private module ImplCommon {
result = viableCallable(call) and cc instanceof CallContextReturn
}
newtype TSummary =
TSummaryVal() or
TSummaryTaint() or
TSummaryReadVal(Content f) or
TSummaryReadTaint(Content f) or
TSummaryTaintStore(Content f)
/**
* A summary of flow through a callable. This can either be value-preserving
* if no additional steps are used, taint-flow if at least one additional step
* is used, or any one of those combined with a store or a read. Summaries
* recorded at a return node are restricted to include at least one additional
* step, as the value-based summaries are calculated independent of the
* configuration.
*/
class Summary extends TSummary {
string toString() {
result = "Val" and this = TSummaryVal()
or
result = "Taint" and this = TSummaryTaint()
or
exists(Content f |
result = "ReadVal " + f.toString() and this = TSummaryReadVal(f)
or
result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f)
or
result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f)
)
}
/** Gets the summary that results from extending this with an additional step. */
Summary additionalStep() {
this = TSummaryVal() and result = TSummaryTaint()
or
this = TSummaryTaint() and result = TSummaryTaint()
or
exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f))
or
exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f))
}
/** Gets the summary that results from extending this with a read. */
Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) }
/** Gets the summary that results from extending this with a store. */
Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) }
/** Gets the summary that results from extending this with `step`. */
bindingset[this, step]
Summary compose(Summary step) {
this = TSummaryVal() and result = step
or
this = TSummaryTaint() and
(step = TSummaryTaint() or step = TSummaryTaintStore(_)) and
result = step
or
exists(Content f |
this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f)
)
or
this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this
}
/** Holds if this summary does not include any taint steps. */
predicate isPartial() {
this = TSummaryVal() or
this = TSummaryReadVal(_)
}
}
pragma[noinline]
DataFlowType getErasedNodeType(Node n) { result = getErasedRepr(n.getType()) }

View File

@@ -59,10 +59,12 @@ class Node extends TIRDataFlowNode {
Parameter asParameter() { result = instr.(InitializeParameterInstruction).getParameter() }
/**
* DEPRECATED: See UninitializedNode.
*
* Gets the uninitialized local variable corresponding to this node, if
* any.
*/
LocalVariable asUninitialized() { result = instr.(UninitializedInstruction).getLocalVariable() }
LocalVariable asUninitialized() { none() }
/**
* Gets an upper bound on the type of this node.
@@ -140,15 +142,19 @@ private class ThisParameterNode extends Node {
}
/**
* DEPRECATED: Data flow was never an accurate way to determine what
* expressions might be uninitialized. It errs on the side of saying that
* everything is uninitialized, and this is even worse in the IR because the IR
* doesn't use syntactic hints to rule out variables that are definitely
* initialized.
*
* The value of an uninitialized local variable, viewed as a node in a data
* flow graph.
*/
class UninitializedNode extends Node {
override UninitializedInstruction instr;
deprecated class UninitializedNode extends Node {
UninitializedNode() { none() }
LocalVariable getLocalVariable() { result = instr.getLocalVariable() }
override string toString() { result = this.getLocalVariable().toString() }
LocalVariable getLocalVariable() { none() }
}
/**
@@ -259,7 +265,21 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or
// Treat all conversions as flow, even conversions between different numeric types.
iTo.(ConvertInstruction).getUnary() = iFrom or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
iTo.(InheritanceConversionInstruction).getUnary() = iFrom or
// A chi instruction represents a point where a new value (the _partial_
// operand) may overwrite an old value (the _total_ operand), but the alias
// analysis couldn't determine that it surely will overwrite every bit of it or
// that it surely will overwrite no bit of it.
//
// By allowing flow through the total operand, we ensure that flow is not lost
// due to shortcomings of the alias analysis. We may get false flow in cases
// where the data is indeed overwritten.
//
// Allowing flow through the partial operand would be more noisy, especially
// for variables that have escaped: for soundness, the IR has to assume that
// every write to an unknown address can affect every escaped variable, and
// this assumption shows up as data flowing through partial chi operands.
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
}
/**

View File

@@ -1,3 +1,7 @@
private import internal.OpcodeImports as Imports
private import internal.OperandTag
import Imports::MemoryAccessKind
private newtype TOpcode =
TNoOp() or
TUninitialized() or
@@ -84,11 +88,67 @@ private newtype TOpcode =
class Opcode extends TOpcode {
string toString() { result = "UnknownOpcode" }
/**
* Gets the kind of memory access performed by this instruction's result.
* Holds only for opcodes with a memory result.
*/
MemoryAccessKind getWriteMemoryAccess() { none() }
/**
* Gets the kind of memory access performed by this instruction's `MemoryOperand`. Holds only for
* opcodes that read from memory.
*/
MemoryAccessKind getReadMemoryAccess() { none() }
/**
* Holds if the instruction has an `AddressOperand`.
*/
predicate hasAddressOperand() { none() }
/**
* Holds if the instruction has a `BufferSizeOperand`.
*/
predicate hasBufferSizeOperand() { none() }
/**
* Holds if the instruction's write memory access is a `may` write, as opposed to a `must` write.
*/
predicate hasMayWriteMemoryAccess() { none() }
/**
* Holds if the instruction's read memory access is a `may` read, as opposed to a `must` read.
*/
predicate hasMayReadMemoryAccess() { none() }
/**
* Holds if the instruction must have an operand with the specified `OperandTag`.
*/
final predicate hasOperand(OperandTag tag) {
hasOperandInternal(tag)
or
hasAddressOperand() and tag instanceof AddressOperandTag
or
hasBufferSizeOperand() and tag instanceof BufferSizeOperandTag
}
/**
* Holds if the instruction must have an operand with the specified `OperandTag`, ignoring
* `AddressOperandTag` and `BufferSizeOperandTag`.
*/
predicate hasOperandInternal(OperandTag tag) { none() }
}
abstract class UnaryOpcode extends Opcode { }
abstract class UnaryOpcode extends Opcode {
final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag }
}
abstract class BinaryOpcode extends Opcode { }
abstract class BinaryOpcode extends Opcode {
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof LeftOperandTag or
tag instanceof RightOperandTag
}
}
abstract class PointerArithmeticOpcode extends BinaryOpcode { }
@@ -122,55 +182,138 @@ abstract class ThrowOpcode extends Opcode { }
abstract class CatchOpcode extends Opcode { }
abstract class OpcodeWithCondition extends Opcode { }
abstract class OpcodeWithCondition extends Opcode {
final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag }
}
abstract class BuiltInOperationOpcode extends Opcode { }
abstract class SideEffectOpcode extends Opcode { }
/**
* An opcode that accesses a single memory location via an `AddressOperand`.
*/
abstract class IndirectMemoryAccessOpcode extends Opcode {
final override predicate hasAddressOperand() { any() }
}
/**
* An opcode that writes to a single memory location via an `AddressOperand`.
*/
abstract class IndirectWriteOpcode extends IndirectMemoryAccessOpcode {
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
* An opcode that reads from a single memory location via an `AddressOperand`.
*/
abstract class IndirectReadOpcode extends IndirectMemoryAccessOpcode {
final override MemoryAccessKind getReadMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
* An opcode that accesses a memory buffer of unknown size.
*/
abstract class BufferAccessOpcode extends Opcode {
final override predicate hasAddressOperand() { any() }
}
/**
* An opcode that writes to a memory buffer of unknown size.
*/
abstract class BufferWriteOpcode extends BufferAccessOpcode {
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
* An opcode that reads from a memory buffer of unknown size.
*/
abstract class BufferReadOpcode extends BufferAccessOpcode {
final override MemoryAccessKind getReadMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
* An opcode that accesses a memory buffer whose size is determined by a `BufferSizeOperand`.
*/
abstract class SizedBufferAccessOpcode extends Opcode {
final override predicate hasAddressOperand() { any() }
final override predicate hasBufferSizeOperand() { any() }
}
/**
* An opcode that writes to a memory buffer whose size is determined by a `BufferSizeOperand`.
*/
abstract class SizedBufferWriteOpcode extends SizedBufferAccessOpcode {
final override MemoryAccessKind getWriteMemoryAccess() {
result instanceof BufferMemoryAccess //TODO: SizedBufferMemoryAccess
}
}
/**
* An opcode that reads from a memory buffer whose size is determined by a `BufferSizeOperand`.
*/
abstract class SizedBufferReadOpcode extends SizedBufferAccessOpcode {
final override MemoryAccessKind getReadMemoryAccess() {
result instanceof BufferMemoryAccess //TODO: SizedBufferMemoryAccess
}
}
/**
* An opcode that might write to any escaped memory location.
*/
abstract class EscapedWriteOpcode extends Opcode {
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess }
}
/**
* An opcode that might read from any escaped memory location.
*/
abstract class EscapedReadOpcode extends Opcode {
final override MemoryAccessKind getReadMemoryAccess() { result instanceof EscapedMemoryAccess }
}
/**
* An opcode whose write memory access is a `may` write, as opposed to a `must` write.
*/
abstract class MayWriteOpcode extends Opcode {
final override predicate hasMayWriteMemoryAccess() { any() }
}
/**
* An opcode whose read memory access is a `may` read, as opposed to a `must` read.
*/
abstract class MayReadOpcode extends Opcode {
final override predicate hasMayReadMemoryAccess() { any() }
}
/**
* An opcode that reads a value from memory.
*/
abstract class OpcodeWithLoad extends MemoryAccessOpcode { }
abstract class OpcodeWithLoad extends IndirectReadOpcode {
final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LoadOperandTag }
}
/**
* An opcode that reads from a set of memory locations as a side effect.
*/
abstract class ReadSideEffectOpcode extends SideEffectOpcode { }
abstract class ReadSideEffectOpcode extends SideEffectOpcode {
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof SideEffectOperandTag
}
}
/**
* An opcode that writes to a set of memory locations as a side effect.
*/
abstract class WriteSideEffectOpcode extends SideEffectOpcode { }
/**
* An opcode that definitely writes to a set of memory locations as a side effect.
*/
abstract class MustWriteSideEffectOpcode extends WriteSideEffectOpcode { }
/**
* An opcode that may overwrite some, all, or none of an existing set of memory locations. Modeled
* as a read of the original contents, plus a "may" write of the new contents.
*/
abstract class MayWriteSideEffectOpcode extends WriteSideEffectOpcode { }
/**
* An opcode that accesses a buffer via an `AddressOperand`.
*/
abstract class BufferAccessOpcode extends MemoryAccessOpcode { }
/**
* An opcode that accesses a buffer via an `AddressOperand` with a `BufferSizeOperand` specifying
* the number of elements accessed.
*/
abstract class SizedBufferAccessOpcode extends BufferAccessOpcode { }
module Opcode {
class NoOp extends Opcode, TNoOp {
final override string toString() { result = "NoOp" }
}
class Uninitialized extends MemoryAccessOpcode, TUninitialized {
class Uninitialized extends IndirectWriteOpcode, TUninitialized {
final override string toString() { result = "Uninitialized" }
}
@@ -178,11 +321,11 @@ module Opcode {
final override string toString() { result = "Error" }
}
class InitializeParameter extends MemoryAccessOpcode, TInitializeParameter {
class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter {
final override string toString() { result = "InitializeParameter" }
}
class InitializeIndirection extends MemoryAccessOpcode, TInitializeIndirection {
class InitializeIndirection extends IndirectWriteOpcode, TInitializeIndirection {
final override string toString() { result = "InitializeIndirection" }
}
@@ -206,8 +349,12 @@ module Opcode {
final override string toString() { result = "ReturnVoid" }
}
class ReturnIndirection extends MemoryAccessOpcode, TReturnIndirection {
class ReturnIndirection extends IndirectReadOpcode, TReturnIndirection {
final override string toString() { result = "ReturnIndirection" }
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof SideEffectOperandTag
}
}
class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue {
@@ -218,8 +365,12 @@ module Opcode {
final override string toString() { result = "Load" }
}
class Store extends CopyOpcode, MemoryAccessOpcode, TStore {
class Store extends CopyOpcode, IndirectWriteOpcode, TStore {
final override string toString() { result = "Store" }
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof StoreValueOperandTag
}
}
class Add extends BinaryArithmeticOpcode, TAdd {
@@ -372,6 +523,10 @@ module Opcode {
class Call extends Opcode, TCall {
final override string toString() { result = "Call" }
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof CallTargetOperandTag
}
}
class CatchByType extends CatchOpcode, TCatchByType {
@@ -396,22 +551,40 @@ module Opcode {
class UnmodeledDefinition extends Opcode, TUnmodeledDefinition {
final override string toString() { result = "UnmodeledDefinition" }
final override MemoryAccessKind getWriteMemoryAccess() {
result instanceof UnmodeledMemoryAccess
}
}
class UnmodeledUse extends Opcode, TUnmodeledUse {
final override string toString() { result = "UnmodeledUse" }
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof UnmodeledUseOperandTag
}
}
class AliasedDefinition extends Opcode, TAliasedDefinition {
final override string toString() { result = "AliasedDefinition" }
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess }
}
class AliasedUse extends Opcode, TAliasedUse {
final override string toString() { result = "AliasedUse" }
final override MemoryAccessKind getReadMemoryAccess() { result instanceof NonLocalMemoryAccess }
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof SideEffectOperandTag
}
}
class Phi extends Opcode, TPhi {
final override string toString() { result = "Phi" }
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess }
}
class BuiltIn extends BuiltInOperationOpcode, TBuiltIn {
@@ -434,64 +607,81 @@ module Opcode {
final override string toString() { result = "VarArgCopy" }
}
class CallSideEffect extends MayWriteSideEffectOpcode, TCallSideEffect {
class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode,
ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect {
final override string toString() { result = "CallSideEffect" }
}
class CallReadSideEffect extends ReadSideEffectOpcode, TCallReadSideEffect {
class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode,
TCallReadSideEffect {
final override string toString() { result = "CallReadSideEffect" }
}
class IndirectReadSideEffect extends ReadSideEffectOpcode, MemoryAccessOpcode,
class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode,
TIndirectReadSideEffect {
final override string toString() { result = "IndirectReadSideEffect" }
}
class IndirectMustWriteSideEffect extends MustWriteSideEffectOpcode, MemoryAccessOpcode,
class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
TIndirectMustWriteSideEffect {
final override string toString() { result = "IndirectMustWriteSideEffect" }
}
class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode,
TIndirectMayWriteSideEffect {
class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
MayWriteOpcode, TIndirectMayWriteSideEffect {
final override string toString() { result = "IndirectMayWriteSideEffect" }
}
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferAccessOpcode, TBufferReadSideEffect {
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferReadOpcode, TBufferReadSideEffect {
final override string toString() { result = "BufferReadSideEffect" }
}
class BufferMustWriteSideEffect extends MustWriteSideEffectOpcode, BufferAccessOpcode,
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, BufferWriteOpcode,
TBufferMustWriteSideEffect {
final override string toString() { result = "BufferMustWriteSideEffect" }
}
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode,
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, BufferWriteOpcode, MayWriteOpcode,
TBufferMayWriteSideEffect {
final override string toString() { result = "BufferMayWriteSideEffect" }
}
class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferAccessOpcode,
class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode,
TSizedBufferReadSideEffect {
final override string toString() { result = "SizedBufferReadSideEffect" }
}
class SizedBufferMustWriteSideEffect extends MustWriteSideEffectOpcode, SizedBufferAccessOpcode,
class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
TSizedBufferMustWriteSideEffect {
final override string toString() { result = "SizedBufferMustWriteSideEffect" }
}
class SizedBufferMayWriteSideEffect extends MayWriteSideEffectOpcode, SizedBufferAccessOpcode,
TSizedBufferMayWriteSideEffect {
class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
MayWriteOpcode, TSizedBufferMayWriteSideEffect {
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
}
class Chi extends Opcode, TChi {
final override string toString() { result = "Chi" }
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof ChiTotalOperandTag
or
tag instanceof ChiPartialOperandTag
}
final override MemoryAccessKind getWriteMemoryAccess() {
result instanceof ChiTotalMemoryAccess
}
}
class InlineAsm extends Opcode, TInlineAsm {
class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode,
MayReadOpcode, TInlineAsm {
final override string toString() { result = "InlineAsm" }
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof SideEffectOperandTag
}
}
class Unreached extends Opcode, TUnreached {

View File

@@ -11,60 +11,12 @@ import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if the instruction `instr` should be expected to have an operand
* with operand tag `tag`. Only holds for singleton operand tags. Tags with
* parameters, such as `PhiInputOperand` and `PositionalArgumentOperand` are handled
* separately in `unexpectedOperand`.
*/
private predicate expectsOperand(Instruction instr, OperandTag tag) {
exists(Opcode opcode |
opcode = instr.getOpcode() and
(
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag
or
opcode instanceof BinaryOpcode and
(
tag instanceof LeftOperandTag or
tag instanceof RightOperandTag
)
or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag
or
opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag
or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag
or
opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag
or
opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag
or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag
or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
or
opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag
or
opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag
or
(
opcode instanceof ReadSideEffectOpcode or
opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect or
opcode instanceof Opcode::ReturnIndirection or
opcode instanceof Opcode::AliasedUse
) and
tag instanceof SideEffectOperandTag
)
)
}
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
expectsOperand(instr, tag) and
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
@@ -84,7 +36,7 @@ module InstructionSanity {
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not expectsOperand(instr, tag) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
@@ -308,6 +260,19 @@ module InstructionSanity {
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.
*/
private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) {
exists(Language::Location location |
irFunc = result.getEnclosingIRFunction() and
location = result.getLocation() and
file = location.getFile() and
line = location.getStartLine()
)
}
/**
* Represents a single operation in the IR.
*/
@@ -372,8 +337,8 @@ class Instruction extends Construction::TInstruction {
private int getLineRank() {
this = rank[result](Instruction instr |
instr.getAST().getFile() = getAST().getFile() and
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
instr = getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(),
getLocation().getStartLine())
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
@@ -549,7 +514,8 @@ class Instruction extends Construction::TInstruction {
* Gets the kind of memory access performed by this instruction's result.
* Holds only for instructions with a memory result.
*/
MemoryAccessKind getResultMemoryAccess() { none() }
pragma[inline]
final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() }
/**
* Holds if the memory access performed by this instruction's result will not always write to
@@ -559,7 +525,8 @@ class Instruction extends Construction::TInstruction {
* location is a conservative estimate of the memory that might actually be accessed at runtime
* (for example, the global side effects of a function call).
*/
predicate hasResultMayMemoryAccess() { none() }
pragma[inline]
final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() }
/**
* Gets the operand that holds the memory address to which this instruction stores its
@@ -710,16 +677,12 @@ class InitializeParameterInstruction extends VariableInstruction {
InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter }
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
class InitializeIndirectionInstruction extends VariableInstruction {
InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection }
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -754,8 +717,6 @@ class ErrorInstruction extends Instruction {
class UninitializedInstruction extends VariableInstruction {
UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
/**
* Gets the variable that is uninitialized.
*/
@@ -821,8 +782,6 @@ class LoadInstruction extends CopyInstruction {
class StoreInstruction extends CopyInstruction {
StoreInstruction() { getOpcode() instanceof Opcode::Store }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
final AddressOperand getDestinationAddressOperand() { result = getAnOperand() }
final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() }
@@ -1236,10 +1195,6 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1303,8 +1258,6 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction
IndirectMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -1315,8 +1268,6 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::BufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
@@ -1328,8 +1279,6 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi
getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
@@ -1342,10 +1291,6 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1354,10 +1299,6 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
*/
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1369,10 +1310,6 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
@@ -1381,10 +1318,6 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
*/
class InlineAsmInstruction extends Instruction {
InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1470,10 +1403,6 @@ class CatchAnyInstruction extends CatchInstruction {
class UnmodeledDefinitionInstruction extends Instruction {
UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition }
final override MemoryAccessKind getResultMemoryAccess() {
result instanceof UnmodeledMemoryAccess
}
}
/**
@@ -1481,8 +1410,6 @@ class UnmodeledDefinitionInstruction extends Instruction {
*/
class AliasedDefinitionInstruction extends Instruction {
AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
}
/**
@@ -1511,8 +1438,6 @@ class UnmodeledUseInstruction extends Instruction {
class PhiInstruction extends Instruction {
PhiInstruction() { getOpcode() instanceof Opcode::Phi }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof PhiMemoryAccess }
/**
* Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block.
*/
@@ -1573,8 +1498,6 @@ class PhiInstruction extends Instruction {
class ChiInstruction extends Instruction {
ChiInstruction() { getOpcode() instanceof Opcode::Chi }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof ChiTotalMemoryAccess }
/**
* Gets the operand that represents the previous state of all memory that might be aliased by the
* memory write.

View File

@@ -170,7 +170,7 @@ class MemoryOperand extends Operand {
/**
* Gets the kind of memory access performed by the operand.
*/
MemoryAccessKind getMemoryAccess() { none() }
MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() }
/**
* Holds if the memory access performed by this operand will not always read from every bit in the
@@ -180,7 +180,7 @@ class MemoryOperand extends Operand {
* conservative estimate of the memory that might actually be accessed at runtime (for example,
* the global side effects of a function call).
*/
predicate hasMayMemoryAccess() { none() }
predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() }
/**
* Returns the operand that holds the memory address from which the current operand loads its
@@ -274,8 +274,6 @@ class LoadOperand extends TypedOperand {
override LoadOperandTag tag;
override string toString() { result = "Load" }
final override MemoryAccessKind getMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -331,8 +329,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand {
override UnmodeledUseOperandTag tag;
override string toString() { result = "UnmodeledUse" }
final override MemoryAccessKind getMemoryAccess() { result instanceof UnmodeledMemoryAccess }
}
/**
@@ -382,50 +378,6 @@ class PositionalArgumentOperand extends ArgumentOperand {
class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag;
override MemoryAccessKind getMemoryAccess() {
useInstr instanceof AliasedUseInstruction and
result instanceof NonLocalMemoryAccess
or
useInstr instanceof CallSideEffectInstruction and
result instanceof EscapedMemoryAccess
or
useInstr instanceof CallReadSideEffectInstruction and
result instanceof EscapedMemoryAccess
or
useInstr instanceof IndirectReadSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferReadSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMustWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferMustWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMayWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferMayWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof ReturnIndirectionInstruction and
result instanceof BufferMemoryAccess
}
final override predicate hasMayMemoryAccess() {
useInstr instanceof AliasedUseInstruction
or
useInstr instanceof CallSideEffectInstruction
or
useInstr instanceof CallReadSideEffectInstruction
or
useInstr instanceof IndirectMayWriteSideEffectInstruction
or
useInstr instanceof BufferMayWriteSideEffectInstruction
}
}
/**

View File

@@ -29,7 +29,7 @@ private predicate hasOperandMemoryAccess(
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, startBitOffset) and
languageType = operand.getLanguageType() and
type = languageType.getIRType() and
(if operand.hasMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
@@ -41,8 +41,18 @@ private newtype TMemoryLocation =
IntValue endBitOffset, boolean isMayAccess
) {
(
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess) or
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
or
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
or
exists(IRAutomaticVariable autoVar |
// Always create a memory location for the entire variable.
autoVar = var and
type = autoVar.getIRType() and
startBitOffset = 0 and
endBitOffset = type.getByteSize() * 8 and
isMayAccess = false
)
) and
languageType = type.getCanonicalLanguageType()
} or
@@ -78,6 +88,8 @@ abstract class MemoryLocation extends TMemoryLocation {
abstract IRFunction getIRFunction();
abstract Location getLocation();
final IRType getIRType() { result = getType().getIRType() }
abstract predicate isMayAccess();
@@ -141,6 +153,8 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
final override Location getLocation() { result = var.getLocation() }
final IntValue getStartBitOffset() { result = startBitOffset }
final IntValue getEndBitOffset() { result = endBitOffset }
@@ -208,6 +222,8 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
final override IRFunction getIRFunction() { result = irFunc }
final override Location getLocation() { result = irFunc.getLocation() }
final override string getUniqueId() { result = "{Unknown}" }
final override predicate isMayAccess() { isMayAccess = true }
@@ -233,6 +249,8 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
final override IRFunction getIRFunction() { result = irFunc }
final override Location getLocation() { result = irFunc.getLocation() }
final override string getUniqueId() { result = "{AllNonLocal}" }
final override predicate isMayAccess() { isMayAccess = true }
@@ -255,6 +273,8 @@ class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
final override IRFunction getIRFunction() { result = irFunc }
final override Location getLocation() { result = irFunc.getLocation() }
final override string getUniqueId() { result = " " + toString() }
final override VirtualVariable getVirtualVariable() { result = TAllAliasedMemory(irFunc, false) }
@@ -401,50 +421,36 @@ private predicate isRelatableMemoryLocation(VariableMemoryLocation vml) {
vml.getStartBitOffset() != Ints::unknown()
}
private predicate isCoveredOffset(
VirtualVariable vv, IRVariable var, int offsetRank, VariableMemoryLocation vml
) {
exists(int startRank, int endRank |
vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vv, offset_)) and
vml.getEndBitOffset() = rank[endRank](IntValue offset_ | isRelevantOffset(vv, offset_)) and
hasVariableAndVirtualVariable(vv, var, vml) and
private predicate isCoveredOffset(IRVariable var, int offsetRank, VariableMemoryLocation vml) {
exists(int startRank, int endRank, VirtualVariable vvar |
vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
vml.getEndBitOffset() = rank[endRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
var = vml.getVariable() and
vvar = vml.getVirtualVariable() and
isRelatableMemoryLocation(vml) and
offsetRank in [startRank .. endRank]
)
}
private predicate hasUnknownOffset(VirtualVariable vv, IRVariable var, VariableMemoryLocation vml) {
hasVariableAndVirtualVariable(vv, var, vml) and
private predicate hasUnknownOffset(IRVariable var, VariableMemoryLocation vml) {
vml.getVariable() = var and
(
vml.getStartBitOffset() = Ints::unknown() or
vml.getEndBitOffset() = Ints::unknown()
)
}
private predicate hasVariableAndVirtualVariable(
VirtualVariable vv, IRVariable var, VariableMemoryLocation vml
) {
var = vml.getVariable() and
vv = vml.getVirtualVariable()
}
private predicate overlappingIRVariableMemoryLocations(
VariableMemoryLocation def, VariableMemoryLocation use
) {
exists(VirtualVariable vv, IRVariable var, int offsetRank |
isCoveredOffset(vv, var, offsetRank, def) and
isCoveredOffset(vv, var, offsetRank, use)
exists(IRVariable var, int offsetRank |
isCoveredOffset(var, offsetRank, def) and
isCoveredOffset(var, offsetRank, use)
)
or
exists(VirtualVariable vv, IRVariable var |
hasUnknownOffset(vv, var, def) and
hasVariableAndVirtualVariable(vv, var, use)
)
hasUnknownOffset(use.getVariable(), def)
or
exists(VirtualVariable vv, IRVariable var |
hasUnknownOffset(vv, var, use) and
hasVariableAndVirtualVariable(vv, var, def)
)
hasUnknownOffset(def.getVariable(), use)
}
private Overlap getVariableMemoryLocationOverlap(
@@ -483,7 +489,7 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
exists(MemoryAccessKind kind, boolean isMayAccess |
kind = operand.getMemoryAccess() and
(if operand.hasMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
(
(
kind.usesAddressOperand() and

View File

@@ -891,4 +891,13 @@ module SSASanity {
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
)
}
query predicate missingVirtualVariableForMemoryLocation(
Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText
) {
not exists(location.getVirtualVariable()) and
func = location.getIRFunction() and
funcText = Language::getIdentityString(func.getFunction()) and
message = "Memory location has no virtual variable in function '$@'."
}
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind

View File

@@ -11,60 +11,12 @@ import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if the instruction `instr` should be expected to have an operand
* with operand tag `tag`. Only holds for singleton operand tags. Tags with
* parameters, such as `PhiInputOperand` and `PositionalArgumentOperand` are handled
* separately in `unexpectedOperand`.
*/
private predicate expectsOperand(Instruction instr, OperandTag tag) {
exists(Opcode opcode |
opcode = instr.getOpcode() and
(
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag
or
opcode instanceof BinaryOpcode and
(
tag instanceof LeftOperandTag or
tag instanceof RightOperandTag
)
or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag
or
opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag
or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag
or
opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag
or
opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag
or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag
or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
or
opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag
or
opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag
or
(
opcode instanceof ReadSideEffectOpcode or
opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect or
opcode instanceof Opcode::ReturnIndirection or
opcode instanceof Opcode::AliasedUse
) and
tag instanceof SideEffectOperandTag
)
)
}
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
expectsOperand(instr, tag) and
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
@@ -84,7 +36,7 @@ module InstructionSanity {
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not expectsOperand(instr, tag) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
@@ -308,6 +260,19 @@ module InstructionSanity {
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.
*/
private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) {
exists(Language::Location location |
irFunc = result.getEnclosingIRFunction() and
location = result.getLocation() and
file = location.getFile() and
line = location.getStartLine()
)
}
/**
* Represents a single operation in the IR.
*/
@@ -372,8 +337,8 @@ class Instruction extends Construction::TInstruction {
private int getLineRank() {
this = rank[result](Instruction instr |
instr.getAST().getFile() = getAST().getFile() and
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
instr = getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(),
getLocation().getStartLine())
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
@@ -549,7 +514,8 @@ class Instruction extends Construction::TInstruction {
* Gets the kind of memory access performed by this instruction's result.
* Holds only for instructions with a memory result.
*/
MemoryAccessKind getResultMemoryAccess() { none() }
pragma[inline]
final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() }
/**
* Holds if the memory access performed by this instruction's result will not always write to
@@ -559,7 +525,8 @@ class Instruction extends Construction::TInstruction {
* location is a conservative estimate of the memory that might actually be accessed at runtime
* (for example, the global side effects of a function call).
*/
predicate hasResultMayMemoryAccess() { none() }
pragma[inline]
final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() }
/**
* Gets the operand that holds the memory address to which this instruction stores its
@@ -710,16 +677,12 @@ class InitializeParameterInstruction extends VariableInstruction {
InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter }
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
class InitializeIndirectionInstruction extends VariableInstruction {
InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection }
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -754,8 +717,6 @@ class ErrorInstruction extends Instruction {
class UninitializedInstruction extends VariableInstruction {
UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
/**
* Gets the variable that is uninitialized.
*/
@@ -821,8 +782,6 @@ class LoadInstruction extends CopyInstruction {
class StoreInstruction extends CopyInstruction {
StoreInstruction() { getOpcode() instanceof Opcode::Store }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
final AddressOperand getDestinationAddressOperand() { result = getAnOperand() }
final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() }
@@ -1236,10 +1195,6 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1303,8 +1258,6 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction
IndirectMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -1315,8 +1268,6 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::BufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
@@ -1328,8 +1279,6 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi
getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
@@ -1342,10 +1291,6 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1354,10 +1299,6 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
*/
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1369,10 +1310,6 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
@@ -1381,10 +1318,6 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
*/
class InlineAsmInstruction extends Instruction {
InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1470,10 +1403,6 @@ class CatchAnyInstruction extends CatchInstruction {
class UnmodeledDefinitionInstruction extends Instruction {
UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition }
final override MemoryAccessKind getResultMemoryAccess() {
result instanceof UnmodeledMemoryAccess
}
}
/**
@@ -1481,8 +1410,6 @@ class UnmodeledDefinitionInstruction extends Instruction {
*/
class AliasedDefinitionInstruction extends Instruction {
AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
}
/**
@@ -1511,8 +1438,6 @@ class UnmodeledUseInstruction extends Instruction {
class PhiInstruction extends Instruction {
PhiInstruction() { getOpcode() instanceof Opcode::Phi }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof PhiMemoryAccess }
/**
* Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block.
*/
@@ -1573,8 +1498,6 @@ class PhiInstruction extends Instruction {
class ChiInstruction extends Instruction {
ChiInstruction() { getOpcode() instanceof Opcode::Chi }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof ChiTotalMemoryAccess }
/**
* Gets the operand that represents the previous state of all memory that might be aliased by the
* memory write.

View File

@@ -170,7 +170,7 @@ class MemoryOperand extends Operand {
/**
* Gets the kind of memory access performed by the operand.
*/
MemoryAccessKind getMemoryAccess() { none() }
MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() }
/**
* Holds if the memory access performed by this operand will not always read from every bit in the
@@ -180,7 +180,7 @@ class MemoryOperand extends Operand {
* conservative estimate of the memory that might actually be accessed at runtime (for example,
* the global side effects of a function call).
*/
predicate hasMayMemoryAccess() { none() }
predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() }
/**
* Returns the operand that holds the memory address from which the current operand loads its
@@ -274,8 +274,6 @@ class LoadOperand extends TypedOperand {
override LoadOperandTag tag;
override string toString() { result = "Load" }
final override MemoryAccessKind getMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -331,8 +329,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand {
override UnmodeledUseOperandTag tag;
override string toString() { result = "UnmodeledUse" }
final override MemoryAccessKind getMemoryAccess() { result instanceof UnmodeledMemoryAccess }
}
/**
@@ -382,50 +378,6 @@ class PositionalArgumentOperand extends ArgumentOperand {
class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag;
override MemoryAccessKind getMemoryAccess() {
useInstr instanceof AliasedUseInstruction and
result instanceof NonLocalMemoryAccess
or
useInstr instanceof CallSideEffectInstruction and
result instanceof EscapedMemoryAccess
or
useInstr instanceof CallReadSideEffectInstruction and
result instanceof EscapedMemoryAccess
or
useInstr instanceof IndirectReadSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferReadSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMustWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferMustWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMayWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferMayWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof ReturnIndirectionInstruction and
result instanceof BufferMemoryAccess
}
final override predicate hasMayMemoryAccess() {
useInstr instanceof AliasedUseInstruction
or
useInstr instanceof CallSideEffectInstruction
or
useInstr instanceof CallReadSideEffectInstruction
or
useInstr instanceof IndirectMayWriteSideEffectInstruction
or
useInstr instanceof BufferMayWriteSideEffectInstruction
}
}
/**

View File

@@ -11,60 +11,12 @@ import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if the instruction `instr` should be expected to have an operand
* with operand tag `tag`. Only holds for singleton operand tags. Tags with
* parameters, such as `PhiInputOperand` and `PositionalArgumentOperand` are handled
* separately in `unexpectedOperand`.
*/
private predicate expectsOperand(Instruction instr, OperandTag tag) {
exists(Opcode opcode |
opcode = instr.getOpcode() and
(
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag
or
opcode instanceof BinaryOpcode and
(
tag instanceof LeftOperandTag or
tag instanceof RightOperandTag
)
or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag
or
opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag
or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag
or
opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag
or
opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag
or
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag
or
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
or
opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag
or
opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag
or
(
opcode instanceof ReadSideEffectOpcode or
opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect or
opcode instanceof Opcode::ReturnIndirection or
opcode instanceof Opcode::AliasedUse
) and
tag instanceof SideEffectOperandTag
)
)
}
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
expectsOperand(instr, tag) and
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
@@ -84,7 +36,7 @@ module InstructionSanity {
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not expectsOperand(instr, tag) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
@@ -308,6 +260,19 @@ module InstructionSanity {
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.
*/
private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) {
exists(Language::Location location |
irFunc = result.getEnclosingIRFunction() and
location = result.getLocation() and
file = location.getFile() and
line = location.getStartLine()
)
}
/**
* Represents a single operation in the IR.
*/
@@ -372,8 +337,8 @@ class Instruction extends Construction::TInstruction {
private int getLineRank() {
this = rank[result](Instruction instr |
instr.getAST().getFile() = getAST().getFile() and
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
instr = getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(),
getLocation().getStartLine())
|
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
@@ -549,7 +514,8 @@ class Instruction extends Construction::TInstruction {
* Gets the kind of memory access performed by this instruction's result.
* Holds only for instructions with a memory result.
*/
MemoryAccessKind getResultMemoryAccess() { none() }
pragma[inline]
final MemoryAccessKind getResultMemoryAccess() { result = getOpcode().getWriteMemoryAccess() }
/**
* Holds if the memory access performed by this instruction's result will not always write to
@@ -559,7 +525,8 @@ class Instruction extends Construction::TInstruction {
* location is a conservative estimate of the memory that might actually be accessed at runtime
* (for example, the global side effects of a function call).
*/
predicate hasResultMayMemoryAccess() { none() }
pragma[inline]
final predicate hasResultMayMemoryAccess() { getOpcode().hasMayWriteMemoryAccess() }
/**
* Gets the operand that holds the memory address to which this instruction stores its
@@ -710,16 +677,12 @@ class InitializeParameterInstruction extends VariableInstruction {
InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter }
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
class InitializeIndirectionInstruction extends VariableInstruction {
InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection }
final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -754,8 +717,6 @@ class ErrorInstruction extends Instruction {
class UninitializedInstruction extends VariableInstruction {
UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
/**
* Gets the variable that is uninitialized.
*/
@@ -821,8 +782,6 @@ class LoadInstruction extends CopyInstruction {
class StoreInstruction extends CopyInstruction {
StoreInstruction() { getOpcode() instanceof Opcode::Store }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
final AddressOperand getDestinationAddressOperand() { result = getAnOperand() }
final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() }
@@ -1236,10 +1195,6 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1303,8 +1258,6 @@ class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction
IndirectMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -1315,8 +1268,6 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::BufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
@@ -1328,8 +1279,6 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi
getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
@@ -1342,10 +1291,6 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1354,10 +1299,6 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
*/
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1369,10 +1310,6 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
@@ -1381,10 +1318,6 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
*/
class InlineAsmInstruction extends Instruction {
InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
final override predicate hasResultMayMemoryAccess() { any() }
}
/**
@@ -1470,10 +1403,6 @@ class CatchAnyInstruction extends CatchInstruction {
class UnmodeledDefinitionInstruction extends Instruction {
UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition }
final override MemoryAccessKind getResultMemoryAccess() {
result instanceof UnmodeledMemoryAccess
}
}
/**
@@ -1481,8 +1410,6 @@ class UnmodeledDefinitionInstruction extends Instruction {
*/
class AliasedDefinitionInstruction extends Instruction {
AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
}
/**
@@ -1511,8 +1438,6 @@ class UnmodeledUseInstruction extends Instruction {
class PhiInstruction extends Instruction {
PhiInstruction() { getOpcode() instanceof Opcode::Phi }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof PhiMemoryAccess }
/**
* Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block.
*/
@@ -1573,8 +1498,6 @@ class PhiInstruction extends Instruction {
class ChiInstruction extends Instruction {
ChiInstruction() { getOpcode() instanceof Opcode::Chi }
final override MemoryAccessKind getResultMemoryAccess() { result instanceof ChiTotalMemoryAccess }
/**
* Gets the operand that represents the previous state of all memory that might be aliased by the
* memory write.

View File

@@ -170,7 +170,7 @@ class MemoryOperand extends Operand {
/**
* Gets the kind of memory access performed by the operand.
*/
MemoryAccessKind getMemoryAccess() { none() }
MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() }
/**
* Holds if the memory access performed by this operand will not always read from every bit in the
@@ -180,7 +180,7 @@ class MemoryOperand extends Operand {
* conservative estimate of the memory that might actually be accessed at runtime (for example,
* the global side effects of a function call).
*/
predicate hasMayMemoryAccess() { none() }
predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() }
/**
* Returns the operand that holds the memory address from which the current operand loads its
@@ -274,8 +274,6 @@ class LoadOperand extends TypedOperand {
override LoadOperandTag tag;
override string toString() { result = "Load" }
final override MemoryAccessKind getMemoryAccess() { result instanceof IndirectMemoryAccess }
}
/**
@@ -331,8 +329,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand {
override UnmodeledUseOperandTag tag;
override string toString() { result = "UnmodeledUse" }
final override MemoryAccessKind getMemoryAccess() { result instanceof UnmodeledMemoryAccess }
}
/**
@@ -382,50 +378,6 @@ class PositionalArgumentOperand extends ArgumentOperand {
class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag;
override MemoryAccessKind getMemoryAccess() {
useInstr instanceof AliasedUseInstruction and
result instanceof NonLocalMemoryAccess
or
useInstr instanceof CallSideEffectInstruction and
result instanceof EscapedMemoryAccess
or
useInstr instanceof CallReadSideEffectInstruction and
result instanceof EscapedMemoryAccess
or
useInstr instanceof IndirectReadSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferReadSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMustWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferMustWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMayWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferMayWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof ReturnIndirectionInstruction and
result instanceof BufferMemoryAccess
}
final override predicate hasMayMemoryAccess() {
useInstr instanceof AliasedUseInstruction
or
useInstr instanceof CallSideEffectInstruction
or
useInstr instanceof CallReadSideEffectInstruction
or
useInstr instanceof IndirectMayWriteSideEffectInstruction
or
useInstr instanceof BufferMayWriteSideEffectInstruction
}
}
/**

View File

@@ -891,4 +891,13 @@ module SSASanity {
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
)
}
query predicate missingVirtualVariableForMemoryLocation(
Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText
) {
not exists(location.getVirtualVariable()) and
func = location.getIRFunction() and
funcText = Language::getIdentityString(func.getFunction()) and
message = "Memory location has no virtual variable in function '$@'."
}
}

View File

@@ -40,7 +40,7 @@ private predicate isVariableModeled(IRVariable var) {
|
bitOffset = 0 and
type.getIRType() = var.getIRType() and
not operand.hasMayMemoryAccess()
not operand.hasMayReadMemoryAccess()
)
}
@@ -55,6 +55,10 @@ class MemoryLocation extends TMemoryLocation {
final string toString() { result = var.toString() }
final Language::Location getLocation() { result = var.getLocation() }
final IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
final IRVariable getIRVariable() { result = var }
final VirtualVariable getVirtualVariable() { result = this }

View File

@@ -13,6 +13,8 @@ class Function = Cpp::Function;
class Location = Cpp::Location;
class File = Cpp::File;
class AST = Cpp::Locatable;
class Type = Cpp::Type;

View File

@@ -29,6 +29,9 @@
| ref.cpp:109:15:109:20 | ref.cpp:132:13:132:15 | AST only |
| ref.cpp:122:23:122:28 | ref.cpp:123:13:123:15 | AST only |
| ref.cpp:125:19:125:24 | ref.cpp:126:13:126:15 | AST only |
| test.cpp:75:7:75:8 | test.cpp:76:8:76:9 | AST only |
| test.cpp:83:7:83:8 | test.cpp:84:8:84:18 | AST only |
| test.cpp:83:7:83:8 | test.cpp:86:8:86:9 | AST only |
| test.cpp:89:28:89:34 | test.cpp:92:8:92:14 | IR only |
| test.cpp:100:13:100:18 | test.cpp:103:10:103:12 | AST only |
| test.cpp:109:9:109:14 | test.cpp:110:10:110:12 | IR only |

View File

@@ -31,9 +31,6 @@
| test.cpp:31:8:31:8 | c | test.cpp:36:13:36:18 | call to source |
| test.cpp:58:10:58:10 | t | test.cpp:50:14:50:19 | call to source |
| test.cpp:71:8:71:9 | x4 | test.cpp:66:30:66:36 | source1 |
| test.cpp:76:8:76:9 | u1 | test.cpp:75:7:75:8 | u1 |
| test.cpp:84:8:84:18 | ... ? ... : ... | test.cpp:83:7:83:8 | u2 |
| test.cpp:86:8:86:9 | i1 | test.cpp:83:7:83:8 | u2 |
| test.cpp:90:8:90:14 | source1 | test.cpp:89:28:89:34 | source1 |
| test.cpp:92:8:92:14 | source1 | test.cpp:89:28:89:34 | source1 |
| test.cpp:110:10:110:12 | (reference dereference) | test.cpp:109:9:109:14 | call to source |

View File

@@ -22,6 +22,5 @@
| taint.cpp:250:8:250:8 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only |
| taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only |
| taint.cpp:350:7:350:7 | taint.cpp:330:6:330:11 | AST only |
| taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only |
| taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only |

View File

@@ -14,3 +14,4 @@
| taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source |
| taint.cpp:291:7:291:7 | y | taint.cpp:275:6:275:11 | call to source |
| taint.cpp:337:7:337:7 | t | taint.cpp:330:6:330:11 | call to source |
| taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source |

View File

@@ -0,0 +1,2 @@
multipleOperandMemoryLocations
missingVirtualVariableForMemoryLocation

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
multipleOperandMemoryLocations
missingVirtualVariableForMemoryLocation

View File

@@ -760,7 +760,7 @@ ssa.cpp:
# 179| r179_6(int *) = Load : &:r179_4, m179_5
# 179| m179_7(unknown) = InitializeIndirection[p] : &:r179_6
# 179| m179_8(unknown) = Chi : total:m179_2, partial:m179_7
# 180| m180_1(unknown) = InlineAsm : ~mu179_3
# 180| m180_1(unknown) = InlineAsm : ~m179_8
# 180| m180_2(unknown) = Chi : total:m179_8, partial:m180_1
# 181| r181_1(glval<int>) = VariableAddress[#return] :
# 181| r181_2(glval<int *>) = VariableAddress[p] :
@@ -811,7 +811,7 @@ ssa.cpp:
# 190| r190_4(glval<unsigned int &>) = VariableAddress[d] :
# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_20
# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_23
# 186| m186_1(unknown) = InlineAsm : ~mu184_3, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6
# 186| m186_1(unknown) = InlineAsm : ~m184_23, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6
# 186| m186_2(unknown) = Chi : total:m184_23, partial:m186_1
# 192| v192_1(void) = NoOp :
# 184| v184_24(void) = ReturnIndirection : &:r184_6, ~m186_2
@@ -901,7 +901,7 @@ ssa.cpp:
# 209| r209_7(void *) = Convert : r209_6
# 209| r209_8(int) = Constant[4] :
# 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8
# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~mu207_3
# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_5
# 209| m209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8
# 209| m209_12(unknown) = Chi : total:m208_3, partial:m209_11
# 210| r210_1(glval<int>) = VariableAddress[#return] :

View File

@@ -0,0 +1,2 @@
multipleOperandMemoryLocations
missingVirtualVariableForMemoryLocation

View File

@@ -0,0 +1,2 @@
multipleOperandMemoryLocations
missingVirtualVariableForMemoryLocation

View File

@@ -92,3 +92,37 @@ void use_printf(float f, double d)
size_t three_chars(unsigned char a, unsigned char b, unsigned char c) {
return a * b * c; // at most 16581375
}
void g(unsigned char uchar1, unsigned char uchar2, unsigned char uchar3, int i) {
unsigned long ulong1, ulong2, ulong3, ulong4, ulong5;
ulong1 = (uchar1 + 1) * (uchar2 + 1); // GOOD
ulong2 = (i + 1) * (uchar2 + 1); // BAD
ulong3 = (uchar1 + 1) * (uchar2 + 1) * (uchar3 + 1); // GOOD
ulong4 = (uchar1 + (uchar1 + 1)) * (uchar2 + 1); // GOOD
ulong5 = (i + (uchar1 + 1)) * (uchar2 + 1); // BAD
ulong5 = (uchar1 + 1073741824) * uchar2; // BAD [NOT DETECTED]
ulong5 = (uchar1 + (1 << 30)) * uchar2; // BAD [NOT DETECTED]
ulong5 = uchar1 * uchar1 * uchar1 * uchar2 * uchar2 * uchar2; // BAD [NOT DETECTED]
ulong5 = (uchar1 + (unsigned short)(-1)) * (uchar2 + (unsigned short)(-1)); // BAD
}
struct A {
short s;
int i;
};
void g2(struct A* a, short n) {
unsigned long ulong1, ulong2;
ulong1 = (a->s - 1) * ((*a).s + 1); // GOOD
ulong2 = a->i * (*a).i; // BAD
}
int global_i;
unsigned char global_uchar;
void g3() {
unsigned long ulong1, ulong2;
ulong1 = global_i * global_i; // BAD
ulong2 = (global_uchar + 1) * 2; // GOOD
}

View File

@@ -7,3 +7,8 @@
| IntMultToLong.c:61:23:61:33 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. |
| IntMultToLong.c:63:23:63:40 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. |
| IntMultToLong.c:75:9:75:13 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'size_t'. |
| IntMultToLong.c:99:14:99:35 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'unsigned long'. |
| IntMultToLong.c:103:14:103:46 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'unsigned long'. |
| IntMultToLong.c:108:14:108:78 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'unsigned long'. |
| IntMultToLong.c:119:14:119:26 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'unsigned long'. |
| IntMultToLong.c:126:14:126:32 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'unsigned long'. |

View File

@@ -13,3 +13,9 @@
| test.cpp:82:7:82:11 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:84:7:84:11 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:92:17:92:22 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:113:6:113:10 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:134:19:134:23 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:138:21:138:25 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:144:32:144:36 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:150:32:150:36 | ... = ... | Use of '=' where '==' may have been intended. |
| test.cpp:153:46:153:50 | ... = ... | Use of '=' where '==' may have been intended. |

View File

@@ -98,3 +98,58 @@ void g(int *i_p, int cond) {
if (y = 1) { // GOOD: y might not be initialized so it is probably intentional.
}
}
template<typename>
void h() {
int x;
if(x = 0) { // GOOD: x is not initialized so this is probably intentional
}
int y = 0;
if((y = 1)) { // GOOD
}
int z = 0;
if(z = 1) { // BAD
}
}
void f() {
h<int>();
}
void f2() {
const char* sz = "abc";
if(sz = "def") { // GOOD: a == comparison with a string literal is probably not the intent here
}
}
void f3(int x, int y) {
if(x == 1 && (y = 2)) { // GOOD: the programmer seems to be okay with unparenthesized
// comparison operands, so the parenthesis was used to mark this
// as an assignment
}
if((x == 1) && (y = 2)) { // BAD
}
long z = x;
if(((z == 42) || (y = 2)) && (x == 1)) { // BAD
}
if((y = 2) && (x == z || x == 1)) { // GOOD
}
if(((x == 42) || x == 1) && (y = 2)) { // BAD
}
if(x == 10 || (x == 42 && x == 1) && (y = 2)) { // GOOD
}
if(x == 10 || ((x == 42) && (y = 2)) && (z == 1)) { // BAD
}
if((x == 10) || ((z == z) && (x == 1)) && (y = 2)) { // BAD
}
}

View File

@@ -201,6 +201,18 @@ struct TemplatedAssignmentBad {
}
};
template<class T>
class Obj3 {
public:
Obj3<T> &subFunc(const Obj3<T> &other) {
return *this;
}
Obj3<T> &operator=(const Obj3<T> &other) {
return subFunc(other); // GOOD (returns *this)
}
};
int main() {
Container c;
c = c;
@@ -211,5 +223,7 @@ int main() {
taGood = 3;
TemplatedAssignmentBad taBad;
taBad = 4;
Obj3<int> obj3_a, obj3_b;
obj3_a = obj3_b;
return 0;
}

View File

@@ -1,5 +1,4 @@
| AV Rule 82.cpp:18:9:18:17 | operator= | Assignment operator in class Bad1 does not return a reference to *this. |
| AV Rule 82.cpp:24:8:24:16 | operator= | Assignment operator in class Bad2 should have return type Bad2&. Otherwise a copy is created at each call. |
| AV Rule 82.cpp:63:29:63:29 | operator= | Assignment operator in class TemplateReturnAssignment<int> does not return a reference to *this. |
| AV Rule 82.cpp:63:29:63:37 | operator= | Assignment operator in class TemplateReturnAssignment<T> does not return a reference to *this. |
| AV Rule 82.cpp:199:52:199:52 | operator= | Assignment operator in class TemplatedAssignmentBad should have return type TemplatedAssignmentBad&. Otherwise a copy is created at each call. |

View File

@@ -94,3 +94,8 @@ void f13_func(int x)
{
if (x < 10) return; // GOOD
}
int f14()
{
__asm__("rdtsc"); // GOOD
}