CPP: Autoformat 'Critical'.

This commit is contained in:
Geoffrey White
2019-04-17 14:17:24 +01:00
parent 45a35a8572
commit e395f5215f
34 changed files with 654 additions and 635 deletions

View File

@@ -26,9 +26,9 @@ predicate choice(LocalScopeVariable v, Stmt branch, string value) {
exists(AnalysedExpr e |
testAndBranch(e, branch) and
(
(e.getNullSuccessor(v) = branch and value = "null")
e.getNullSuccessor(v) = branch and value = "null"
or
(e.getNonNullSuccessor(v) = branch and value = "non-null")
e.getNonNullSuccessor(v) = branch and value = "non-null"
)
)
}
@@ -60,9 +60,9 @@ where
exists(cond.getNullSuccessor(v)) and
not addressLeak(v, branch.getChildStmt*()) and
(
(cond.isNullCheck(v) and test = "null")
cond.isNullCheck(v) and test = "null"
or
(cond.isValidCheck(v) and test = "non-null")
cond.isValidCheck(v) and test = "non-null"
) and
(if context = test then testresult = "succeed" else testresult = "fail")
select cond,

View File

@@ -7,28 +7,30 @@
* @tags maintainability
* external/cwe/cwe-561
*/
import cpp
predicate limitedScope(Function f)
{
(f.isStatic() and not (f instanceof MemberFunction))
predicate limitedScope(Function f) {
f.isStatic() and not f instanceof MemberFunction
or
f.(MemberFunction).isPrivate()
}
predicate uncalled(Function f)
{
limitedScope(f)
and not exists(Function g |
g = f or g = f.(VirtualFunction).getAnOverriddenFunction+() |
exists(g.getACallToThisFunction()) or
exists(FunctionAccess fa | fa.getTarget() = g))
predicate uncalled(Function f) {
limitedScope(f) and
not exists(Function g | g = f or g = f.(VirtualFunction).getAnOverriddenFunction+() |
exists(g.getACallToThisFunction()) or
exists(FunctionAccess fa | fa.getTarget() = g)
)
}
from Function f
where uncalled(f)
and forall(Function instance | f.(TemplateFunction).getAnInstantiation() = instance | uncalled(instance))
where
uncalled(f) and
forall(Function instance | f.(TemplateFunction).getAnInstantiation() = instance |
uncalled(instance)
) and
// tweaks for good results:
and exists(f.getBlock())
and not(f instanceof Constructor or f instanceof Destructor or f.hasName("operator="))
exists(f.getBlock()) and
not (f instanceof Constructor or f instanceof Destructor or f.hasName("operator="))
select f, "Dead Code: this function is never called."

View File

@@ -1,6 +1,6 @@
/**
* @name Dead code due to goto or break statement
* @description A goto or break statement is followed by unreachable code.
* @description A goto or break statement is followed by unreachable code.
* @kind problem
* @problem.severity warning
* @precision high
@@ -21,16 +21,17 @@ Stmt getNextRealStmt(Block b, int i) {
}
from JumpStmt js, Block b, int i, Stmt s
where b.getStmt(i) = js
and s = getNextRealStmt(b, i)
where
b.getStmt(i) = js and
s = getNextRealStmt(b, i) and
// the next statement isn't jumped to
and not s instanceof LabelStmt
and not s instanceof SwitchCase
not s instanceof LabelStmt and
not s instanceof SwitchCase and
// the next statement isn't breaking out of a switch
and not s.(BreakStmt).getBreakable() instanceof SwitchStmt
not s.(BreakStmt).getBreakable() instanceof SwitchStmt and
// the next statement isn't a loop that can be jumped into
and not exists (LabelStmt ls | s.(Loop).getStmt().getAChild*() = ls)
and not exists (SwitchCase sc | s.(Loop).getStmt().getAChild*() = sc)
not exists(LabelStmt ls | s.(Loop).getStmt().getAChild*() = ls) and
not exists(SwitchCase sc | s.(Loop).getStmt().getAChild*() = sc) and
// no preprocessor logic applies
and not functionContainsPreprocCode(js.getEnclosingFunction())
not functionContainsPreprocCode(js.getEnclosingFunction())
select js, "This statement makes $@ unreachable.", s, s.toString()

View File

@@ -8,54 +8,53 @@
* security
* external/cwe/cwe-775
*/
import semmle.code.cpp.pointsto.PointsTo
import Negativity
predicate closeCall(FunctionCall fc, Variable v)
{
(fc.getTarget().hasQualifiedName("close") and v.getAnAccess() = fc.getArgument(0))
predicate closeCall(FunctionCall fc, Variable v) {
fc.getTarget().hasQualifiedName("close") and v.getAnAccess() = fc.getArgument(0)
or
exists(FunctionCall midcall, Function mid, int arg |
fc.getArgument(arg) = v.getAnAccess() and
fc.getTarget() = mid and
midcall.getEnclosingFunction() = mid and
closeCall(midcall, mid.getParameter(arg)))
closeCall(midcall, mid.getParameter(arg))
)
}
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def)
{
exists(Expr expr |
exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
}
predicate openReaches(ControlFlowNode def, ControlFlowNode node)
{
exists(LocalScopeVariable v |
openDefinition(v, def) and node = def.getASuccessor())
predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
exists(LocalScopeVariable v | openDefinition(v, def) and node = def.getASuccessor())
or
exists(LocalScopeVariable v, ControlFlowNode mid |
openDefinition(v, def) and
openReaches(def, mid) and
not(errorSuccessor(v, mid)) and
not(closeCall(mid, v)) and
not(assignedToFieldOrGlobal(v, mid)) and
node = mid.getASuccessor())
not errorSuccessor(v, mid) and
not closeCall(mid, v) and
not assignedToFieldOrGlobal(v, mid) and
node = mid.getASuccessor()
)
}
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign)
{
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
exists(Variable external |
assign.getRValue() = v.getAnAccess() and
assign.getLValue().(VariableAccess).getTarget() = external and
(external instanceof Field or external instanceof GlobalVariable))
(external instanceof Field or external instanceof GlobalVariable)
)
}
from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret
where openDefinition(v, def)
and openReaches(def, ret)
and checkedSuccess(v, ret)
and not(ret.getExpr().getAChild*() = v.getAnAccess())
and exists(ReturnStmt other | other.getExpr() = v.getAnAccess())
where
openDefinition(v, def) and
openReaches(def, ret) and
checkedSuccess(v, ret) and
not ret.getExpr().getAChild*() = v.getAnAccess() and
exists(ReturnStmt other | other.getExpr() = v.getAnAccess())
select ret,
"Descriptor assigned to '" + v.getName().toString() + "' (line " +
def.getLocation().getStartLine().toString() + ") may not be closed."
def.getLocation().getStartLine().toString() + ") may not be closed."

View File

@@ -8,22 +8,24 @@
* security
* external/cwe/cwe-775
*/
import semmle.code.cpp.pointsto.PointsTo
predicate closed(Expr e)
{
predicate closed(Expr e) {
exists(FunctionCall fc |
fc.getTarget().hasQualifiedName("close") and
fc.getArgument(0) = e)
fc.getArgument(0) = e
)
}
class ClosedExpr extends PointsToExpr
{
class ClosedExpr extends PointsToExpr {
ClosedExpr() { closed(this) }
override predicate interesting() { closed(this) }
}
from Expr alloc
where allocateDescriptorCall(alloc)
and not exists(ClosedExpr closed | closed.pointsTo() = alloc)
where
allocateDescriptorCall(alloc) and
not exists(ClosedExpr closed | closed.pointsTo() = alloc)
select alloc, "This file descriptor is never closed"

View File

@@ -1,18 +1,17 @@
import semmle.code.cpp.pointsto.PointsTo
predicate closed(Expr e) {
fcloseCall(_, e) or
exists(ExprCall c |
// cautiously assume that any ExprCall could be a call to fclose.
c.getAnArgument() = e
)
fcloseCall(_, e) or
exists(ExprCall c |
// cautiously assume that any ExprCall could be a call to fclose.
c.getAnArgument() = e
)
}
class ClosedExpr extends PointsToExpr {
ClosedExpr() { closed(this) }
override predicate interesting() { closed(this) }
ClosedExpr() { closed(this) }
override predicate interesting() { closed(this) }
}
predicate fopenCallMayBeClosed(FunctionCall fc) {
fopenCall(fc) and anythingPointsTo(fc)
}
predicate fopenCallMayBeClosed(FunctionCall fc) { fopenCall(fc) and anythingPointsTo(fc) }

View File

@@ -8,6 +8,7 @@
* security
* external/cwe/cwe-775
*/
import FileClosed
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
@@ -15,8 +16,7 @@ import semmle.code.cpp.controlflow.LocalScopeVariableReachability
* Extend the NullValue class used by Nullness.qll to include simple -1 as a 'null' value
* (for example 'open' returns -1 if there was an error)
*/
class MinusOne extends NullValue
{
class MinusOne extends NullValue {
MinusOne() { this.(UnaryMinusExpr).getOperand().(Literal).getValue() = "1" }
}
@@ -24,29 +24,27 @@ class MinusOne extends NullValue
* 'call' is either a direct call to f, or a possible call to f
* via a function pointer.
*/
predicate mayCallFunction(Expr call, Function f)
{
predicate mayCallFunction(Expr call, Function f) {
call.(FunctionCall).getTarget() = f or
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() = f
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() =
f
}
predicate fopenCallOrIndirect(Expr e)
{
(
// direct fopen call
fopenCall(e) and
// We are only interested in fopen calls that are
// actually closed somehow, as FileNeverClosed
// will catch those that aren't.
fopenCallMayBeClosed(e)
) or exists(ReturnStmt rtn |
predicate fopenCallOrIndirect(Expr e) {
// direct fopen call
fopenCall(e) and
// We are only interested in fopen calls that are
// actually closed somehow, as FileNeverClosed
// will catch those that aren't.
fopenCallMayBeClosed(e)
or
exists(ReturnStmt rtn |
// indirect fopen call
mayCallFunction(e, rtn.getEnclosingFunction()) and
(
// return fopen
fopenCallOrIndirect(rtn.getExpr()) or
fopenCallOrIndirect(rtn.getExpr())
or
// return variable assigned with fopen
exists(Variable v |
v = rtn.getExpr().(VariableAccess).getTarget() and
@@ -57,8 +55,7 @@ predicate fopenCallOrIndirect(Expr e)
)
}
predicate fcloseCallOrIndirect(FunctionCall fc, Variable v)
{
predicate fcloseCallOrIndirect(FunctionCall fc, Variable v) {
// direct fclose call
fcloseCall(fc, v.getAnAccess())
or
@@ -71,11 +68,8 @@ predicate fcloseCallOrIndirect(FunctionCall fc, Variable v)
)
}
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def)
{
exists(Expr expr |
exprDefinition(v, def, expr) and fopenCallOrIndirect(expr)
)
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr))
}
class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
@@ -86,11 +80,10 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
}
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
// node may be used in fopenReaches
// node may be used in fopenReaches
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
fcloseCallOrIndirect(node, v) or
assignedToFieldOrGlobal(v, node) or
// node may be used directly in query
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
@@ -103,17 +96,14 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
/**
* The value from fopen at `def` is still held in Variable `v` upon entering `node`.
*/
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node)
{
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
exists(FOpenVariableReachability r |
// reachability
r.reachesTo(def, _, node, v) or
r.reachesTo(def, _, node, v)
or
// accept def node itself
(
r.isSource(def, v) and
node = def
)
r.isSource(def, v) and
node = def
)
}
@@ -128,10 +118,11 @@ class FOpenReachability extends LocalScopeVariableReachabilityExt {
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v) {
override predicate isBarrier(
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
) {
isSource(source, v) and
next = node.getASuccessor() and
// the file (stored in any variable `v0`) opened at `source` is closed or
// assigned to a global at node, or NULL checked on the edge node -> next.
exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) |
@@ -147,30 +138,26 @@ class FOpenReachability extends LocalScopeVariableReachabilityExt {
* or potentially leaked globally upon reaching `node` (regardless of what variable
* it's still held in, if any).
*/
predicate fopenReaches(ControlFlowNode def, ControlFlowNode node)
{
exists(FOpenReachability r |
r.reaches(def, _, node)
)
predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) {
exists(FOpenReachability r | r.reaches(def, _, node))
}
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e)
{
(
// assigned to anything except a LocalScopeVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
) or exists(Expr midExpr, Function mid, int arg |
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
// assigned to anything except a LocalScopeVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
or
exists(Expr midExpr, Function mid, int arg |
// indirect assignment
e.(FunctionCall).getArgument(arg) = v.getAnAccess() and
mayCallFunction(e, mid) and
midExpr.getEnclosingFunction() = mid and
assignedToFieldOrGlobal(mid.getParameter(arg), midExpr)
) or (
// assigned to a field via constructor field initializer
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
)
or
// assigned to a field via constructor field initializer
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
}
from ControlFlowNode def, ReturnStmt ret
@@ -180,6 +167,4 @@ where
fopenVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
select
def, "The file opened here may not be closed at $@.",
ret, "this exit point"
select def, "The file opened here may not be closed at $@.", ret, "this exit point"

View File

@@ -8,6 +8,7 @@
* security
* external/cwe/cwe-775
*/
import FileClosed
from Expr alloc

View File

@@ -8,103 +8,99 @@
* security
* external/cwe/cwe-457
*/
import cpp
import semmle.code.cpp.pointsto.CallGraph
predicate initFunc(GlobalVariable v, Function f)
{
predicate initFunc(GlobalVariable v, Function f) {
exists(VariableAccess access |
v.getAnAccess() = access and
access.isUsedAsLValue() and
access.getEnclosingFunction() = f)
access.getEnclosingFunction() = f
)
}
predicate useFunc(GlobalVariable v, Function f)
{
predicate useFunc(GlobalVariable v, Function f) {
exists(VariableAccess access |
v.getAnAccess() = access and
access.isRValue() and
access.getEnclosingFunction() = f)
and
access.getEnclosingFunction() = f
) and
not initFunc(v, f)
}
predicate uninitialisedBefore(GlobalVariable v, Function f)
{
predicate uninitialisedBefore(GlobalVariable v, Function f) {
f.hasQualifiedName("main")
or
exists(Call call, Function g |
uninitialisedBefore(v, g) and
call.getEnclosingFunction() = g and
(not functionInitialises(f, v) or locallyUninitialisedAt(v, call)) and
resolvedCall(call, f))
resolvedCall(call, f)
)
}
predicate functionInitialises(Function f, GlobalVariable v)
{
predicate functionInitialises(Function f, GlobalVariable v) {
exists(Call call |
call.getEnclosingFunction() = f and
initialisedBy(v, call))
initialisedBy(v, call)
)
}
// this predicate is restricted to global variables used in the
// same function as "call"
predicate locallyUninitialisedAt(GlobalVariable v, Call call)
{
predicate locallyUninitialisedAt(GlobalVariable v, Call call) {
functionInitialises(call.getEnclosingFunction(), v) and
(
firstCall(call)
or
exists(Call mid |
locallyUninitialisedAt(v, mid) and not initialisedBy(v, mid) and callPair(mid, call))
locallyUninitialisedAt(v, mid) and not initialisedBy(v, mid) and callPair(mid, call)
)
)
}
predicate initialisedBy(GlobalVariable v, Call call)
{
predicate initialisedBy(GlobalVariable v, Call call) {
exists(Function f |
resolvedCall(call, f) and
initialises(v, f))
initialises(v, f)
)
}
predicate initialises(GlobalVariable v, Function f)
{
predicate initialises(GlobalVariable v, Function f) {
initFunc(v, f)
or
exists(Function mid | initialises(v, mid) and allCalls(f, mid))
}
predicate firstCall(Call call)
{
beforeCall(call)
}
predicate firstCall(Call call) { beforeCall(call) }
predicate beforeCall(ControlFlowNode node)
{
predicate beforeCall(ControlFlowNode node) {
exists(Function f | f.getBlock() = node)
or
exists(ControlFlowNode mid |
beforeCall(mid) and
not mid instanceof Call and
node = mid.getASuccessor())
node = mid.getASuccessor()
)
}
predicate callPair(Call call, Call successor)
{
callReaches(call, successor)
}
predicate callPair(Call call, Call successor) { callReaches(call, successor) }
predicate callReaches(Call call, ControlFlowNode successor)
{
predicate callReaches(Call call, ControlFlowNode successor) {
call.getASuccessor() = successor
or
exists(ControlFlowNode mid |
callReaches(call, mid) and
not mid instanceof Call
and mid.getASuccessor() = successor)
not mid instanceof Call and
mid.getASuccessor() = successor
)
}
from GlobalVariable v, Function f
where uninitialisedBefore(v, f)
and useFunc(v, f)
select f, "The variable '" + v.getName() + " is used in this function but may not be initialized when it is called."
where
uninitialisedBefore(v, f) and
useFunc(v, f)
select f,
"The variable '" + v.getName() +
" is used in this function but may not be initialized when it is called."

View File

@@ -8,16 +8,22 @@
* security
* external/cwe/cwe-476
*/
import cpp
from LocalScopeVariable v, ControlFlowNode def,
VariableAccess checked, VariableAccess unchecked
where checked = v.getAnAccess() and dereferenced(checked)
and unchecked = v.getAnAccess() and dereferenced(unchecked)
and definitionUsePair(v, def, checked)
and definitionUsePair(v, def, unchecked)
and checkedValid(v, checked)
and not(checkedValid(v, unchecked))
and not(unchecked.getParent+() instanceof SizeofOperator)
and forall(ControlFlowNode other | definitionUsePair(v, other, checked) | definitionUsePair(v, other, unchecked))
select unchecked, "This dereference is not guarded by a non-null check, whereas other dereferences are guarded"
from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
where
checked = v.getAnAccess() and
dereferenced(checked) and
unchecked = v.getAnAccess() and
dereferenced(unchecked) and
definitionUsePair(v, def, checked) and
definitionUsePair(v, def, unchecked) and
checkedValid(v, checked) and
not checkedValid(v, unchecked) and
not unchecked.getParent+() instanceof SizeofOperator and
forall(ControlFlowNode other | definitionUsePair(v, other, checked) |
definitionUsePair(v, other, unchecked)
)
select unchecked,
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded"

View File

@@ -8,36 +8,35 @@
* security
* external/cwe/cwe-456
*/
import cpp
import semmle.code.cpp.pointsto.CallGraph
predicate global(GlobalVariable v)
{
not exists(v.getInitializer())
and not v.getType() instanceof ArrayType
and not v.getType() instanceof Class
and v.getAnAccess().isUsedAsLValue()
predicate global(GlobalVariable v) {
not exists(v.getInitializer()) and
not v.getType() instanceof ArrayType and
not v.getType() instanceof Class and
v.getAnAccess().isUsedAsLValue()
}
predicate mainCalled(Function f)
{
predicate mainCalled(Function f) {
f.getQualifiedName() = "main"
or
exists(Function caller |
mainCalled(caller) and allCalls(caller, f))
exists(Function caller | mainCalled(caller) and allCalls(caller, f))
}
predicate called(Function f)
{
predicate called(Function f) {
mainCalled(f)
or
exists(FunctionAccess fa | fa.getTarget() = f)
}
from GlobalVariable v
where global(v)
and not exists(VariableAccess lval |
v.getAnAccess() = lval and lval.isUsedAsLValue() and
called(lval.getEnclosingFunction())
)
where
global(v) and
not exists(VariableAccess lval |
v.getAnAccess() = lval and
lval.isUsedAsLValue() and
called(lval.getEnclosingFunction())
)
select v, "Initialization code for '" + v.getName() + "' is never run."

View File

@@ -10,15 +10,17 @@
* statistical
* non-attributable
*/
import cpp
from Function f, Parameter p, Type t, int size
where f.getAParameter() = p
and p.getType() = t
and t.getSize() = size
and size > 64
and not t.getUnderlyingType() instanceof ArrayType
and not f instanceof CopyAssignmentOperator
select
p, "This parameter of type $@ is " + size.toString() + " bytes - consider passing a const pointer/reference instead.",
t, t.toString()
where
f.getAParameter() = p and
p.getType() = t and
t.getSize() = size and
size > 64 and
not t.getUnderlyingType() instanceof ArrayType and
not f instanceof CopyAssignmentOperator
select p,
"This parameter of type $@ is " + size.toString() +
" bytes - consider passing a const pointer/reference instead.", t, t.toString()

View File

@@ -1,7 +1,7 @@
/**
* @name Pointer offset used before it is checked
* @description Accessing a pointer or array using an offset before
* checking if the value is positive
* @description Accessing a pointer or array using an offset before
* checking if the value is positive
* may result in unexpected behavior.
* @kind problem
* @id cpp/late-negative-test
@@ -10,32 +10,42 @@
* security
* external/cwe/cwe-823
*/
import cpp
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op)
{
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
exists(int varindex, string constant, Literal lit |
op.getChild(varindex) = v.getAnAccess() and
op.getChild(1 - varindex) = lit and
lit.getValue() = constant and
(
(op.getOperator() = "<" and varindex = 0 and constant = "0") or
(op.getOperator() = "<" and varindex = 1 and constant = "-1") or
(op.getOperator() = ">" and varindex = 0 and constant = "-1") or
(op.getOperator() = ">" and varindex = 1 and constant = "0") or
(op.getOperator() = "<=" and varindex = 0 and constant = "-1") or
(op.getOperator() = "<=" and varindex = 1 and constant = "0") or
(op.getOperator() = ">=" and varindex = 0 and constant = "0") or
(op.getOperator() = ">=" and varindex = 1 and constant = "-1")
op.getOperator() = "<" and varindex = 0 and constant = "0"
or
op.getOperator() = "<" and varindex = 1 and constant = "-1"
or
op.getOperator() = ">" and varindex = 0 and constant = "-1"
or
op.getOperator() = ">" and varindex = 1 and constant = "0"
or
op.getOperator() = "<=" and varindex = 0 and constant = "-1"
or
op.getOperator() = "<=" and varindex = 1 and constant = "0"
or
op.getOperator() = ">=" and varindex = 0 and constant = "0"
or
op.getOperator() = ">=" and varindex = 1 and constant = "-1"
)
)
}
from LocalScopeVariable v, ArrayExpr dangerous, Expr check
where useUsePair(v, dangerous.getArrayOffset(), check.getAChild())
and negativeCheck(v, check)
and not exists(Expr other | negativeCheck(v, other) and useUsePair(v, other.getAChild(), dangerous.getArrayOffset()))
where
useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and
negativeCheck(v, check) and
not exists(Expr other |
negativeCheck(v, other) and useUsePair(v, other.getAChild(), dangerous.getArrayOffset())
)
select dangerous,
"Variable '" + v.getName() +
"' is used as an array-offset before it is tested for being negative (test on line " +
check.getLocation().getStartLine().toString() + "). "
"' is used as an array-offset before it is tested for being negative (test on line " +
check.getLocation().getStartLine().toString() + "). "

View File

@@ -1,33 +1,27 @@
/** Provides helpers for OverflowStatic.ql */
import cpp
class ZeroAssignment extends AssignExpr
{
class ZeroAssignment extends AssignExpr {
ZeroAssignment() {
this.getAnOperand() instanceof VariableAccess and
this.getAnOperand() instanceof Zero
}
Variable assignedVariable() {
result.getAnAccess() = this.getAnOperand()
}
Variable assignedVariable() { result.getAnAccess() = this.getAnOperand() }
}
private predicate staticLimit(RelationalOperation op, Variable v, int limit)
{
(
op instanceof LTExpr and
op.getLeftOperand() = v.getAnAccess() and
op.getRightOperand().getValue().toInt() - 1 = limit
) or (
op instanceof LEExpr and
op.getLeftOperand() = v.getAnAccess() and
op.getRightOperand().getValue().toInt() = limit
)
private predicate staticLimit(RelationalOperation op, Variable v, int limit) {
op instanceof LTExpr and
op.getLeftOperand() = v.getAnAccess() and
op.getRightOperand().getValue().toInt() - 1 = limit
or
op instanceof LEExpr and
op.getLeftOperand() = v.getAnAccess() and
op.getRightOperand().getValue().toInt() = limit
}
private predicate simpleInc(IncrementOperation inc, Variable v)
{
private predicate simpleInc(IncrementOperation inc, Variable v) {
inc.getAChild() = v.getAnAccess()
}
@@ -35,8 +29,7 @@ private predicate simpleInc(IncrementOperation inc, Variable v)
* A `for` loop of the form `for (x = 0; x < limit; x++)` with no modification
* of `x` in the body. Variations with `<=` and `++x` are allowed.
*/
class ClassicForLoop extends ForStmt
{
class ClassicForLoop extends ForStmt {
ClassicForLoop() {
exists(LocalVariable v |
this.getInitialization().getAChild() instanceof ZeroAssignment and
@@ -51,13 +44,11 @@ class ClassicForLoop extends ForStmt
}
/** Gets the loop variable. */
LocalVariable counter() {
simpleInc(this.getUpdate(), result)
}
LocalVariable counter() { simpleInc(this.getUpdate(), result) }
/** Gets the maximum value that the loop variable may have inside the loop
* body. The minimum is 0. */
int limit() {
staticLimit(this.getCondition(), _, result)
}
/**
* Gets the maximum value that the loop variable may have inside the loop
* body. The minimum is 0.
*/
int limit() { staticLimit(this.getCondition(), _, result) }
}

View File

@@ -1,26 +1,25 @@
import semmle.code.cpp.pointsto.PointsTo
private predicate freed(Expr e)
{
private predicate freed(Expr e) {
exists(FunctionCall fc, Expr arg |
freeCall(fc, arg) and
arg = e
) or exists(DeleteExpr de |
de.getExpr() = e
) or exists(DeleteArrayExpr de |
de.getExpr() = e
) or exists(ExprCall c |
)
or
exists(DeleteExpr de | de.getExpr() = e)
or
exists(DeleteArrayExpr de | de.getExpr() = e)
or
exists(ExprCall c |
// cautiously assume that any ExprCall could be a freeCall.
c.getAnArgument() = e
)
}
class FreedExpr extends PointsToExpr
{
class FreedExpr extends PointsToExpr {
FreedExpr() { freed(this) }
override predicate interesting() { freed(this) }
}
predicate allocMayBeFreed(Expr alloc) {
isAllocationExpr(alloc) and anythingPointsTo(alloc)
}
predicate allocMayBeFreed(Expr alloc) { isAllocationExpr(alloc) and anythingPointsTo(alloc) }

View File

@@ -8,6 +8,7 @@
* security
* external/cwe/cwe-401
*/
import MemoryFreed
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
@@ -15,29 +16,27 @@ import semmle.code.cpp.controlflow.LocalScopeVariableReachability
* 'call' is either a direct call to f, or a possible call to f
* via a function pointer.
*/
predicate mayCallFunction(Expr call, Function f)
{
predicate mayCallFunction(Expr call, Function f) {
call.(FunctionCall).getTarget() = f or
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() = f
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() =
f
}
predicate allocCallOrIndirect(Expr e)
{
(
// direct alloc call
isAllocationExpr(e) and
// We are only interested in alloc calls that are
// actually freed somehow, as MemoryNeverFreed
// will catch those that aren't.
allocMayBeFreed(e)
) or exists(ReturnStmt rtn |
predicate allocCallOrIndirect(Expr e) {
// direct alloc call
isAllocationExpr(e) and
// We are only interested in alloc calls that are
// actually freed somehow, as MemoryNeverFreed
// will catch those that aren't.
allocMayBeFreed(e)
or
exists(ReturnStmt rtn |
// indirect alloc call
mayCallFunction(e, rtn.getEnclosingFunction()) and
(
// return alloc
allocCallOrIndirect(rtn.getExpr()) or
allocCallOrIndirect(rtn.getExpr())
or
// return variable assigned with alloc
exists(Variable v |
v = rtn.getExpr().(VariableAccess).getTarget() and
@@ -53,8 +52,7 @@ predicate allocCallOrIndirect(Expr e)
* succeed. A failed realloc does *not* free the input pointer, which
* can cause memory leaks.
*/
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified)
{
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified) {
reallocCall.getTarget().hasQualifiedName("realloc") and
reallocCall.getArgument(0) = v.getAnAccess() and
(
@@ -64,35 +62,33 @@ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode
newV.getAnAssignedValue() = reallocCall and
node.(AnalysedExpr).getNonNullSuccessor(newV) = verified and
// note: this case uses naive flow logic (getAnAssignedValue).
// special case: if the result of the 'realloc' is assigned to the
// same variable, we don't descriminate properly between the old
// and the new allocation; better to not consider this a free at
// all in that case.
newV != v
) or (
// a realloc(ptr, 0), which always succeeds and frees
// (return the realloc itself)
reallocCall.getArgument(1).getValue() = "0" and
verified = reallocCall
)
or
// a realloc(ptr, 0), which always succeeds and frees
// (return the realloc itself)
reallocCall.getArgument(1).getValue() = "0" and
verified = reallocCall
)
}
predicate freeCallOrIndirect(ControlFlowNode n, Variable v)
{
(
// direct free call
freeCall(n, v.getAnAccess()) and
not n.(FunctionCall).getTarget().hasQualifiedName("realloc")
) or (
// verified realloc call
verifiedRealloc(_, v, n)
) or (
n.(DeleteExpr).getExpr() = v.getAnAccess()
) or (
n.(DeleteArrayExpr).getExpr() = v.getAnAccess()
) or exists(FunctionCall midcall, Function mid, int arg |
predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
// direct free call
freeCall(n, v.getAnAccess()) and
not n.(FunctionCall).getTarget().hasQualifiedName("realloc")
or
// verified realloc call
verifiedRealloc(_, v, n)
or
n.(DeleteExpr).getExpr() = v.getAnAccess()
or
n.(DeleteArrayExpr).getExpr() = v.getAnAccess()
or
exists(FunctionCall midcall, Function mid, int arg |
// indirect free call
n.(Call).getArgument(arg) = v.getAnAccess() and
mayCallFunction(n, mid) and
@@ -101,11 +97,8 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v)
)
}
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def)
{
exists(Expr expr |
exprDefinition(v, def, expr) and allocCallOrIndirect(expr)
)
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr))
}
class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
@@ -116,11 +109,10 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
}
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
// node may be used in allocationReaches
// node may be used in allocationReaches
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
freeCallOrIndirect(node, v) or
assignedToFieldOrGlobal(v, node) or
// node may be used directly in query
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
@@ -133,17 +125,14 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
/**
* The value from allocation `def` is still held in Variable `v` upon entering `node`.
*/
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node)
{
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
exists(AllocVariableReachability r |
// reachability
r.reachesTo(def, _, node, v) or
r.reachesTo(def, _, node, v)
or
// accept def node itself
(
r.isSource(def, v) and
node = def
)
r.isSource(def, v) and
node = def
)
}
@@ -158,10 +147,11 @@ class AllocReachability extends LocalScopeVariableReachabilityExt {
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v) {
override predicate isBarrier(
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
) {
isSource(source, v) and
next = node.getASuccessor() and
// the memory (stored in any variable `v0`) allocated at `source` is freed or
// assigned to a global at node, or NULL checked on the edge node -> next.
exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) |
@@ -177,30 +167,26 @@ class AllocReachability extends LocalScopeVariableReachabilityExt {
* or potentially leaked globally upon reaching `node` (regardless of what variable
* it's still held in, if any).
*/
predicate allocationReaches(ControlFlowNode def, ControlFlowNode node)
{
exists(AllocReachability r |
r.reaches(def, _, node)
)
predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) {
exists(AllocReachability r | r.reaches(def, _, node))
}
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e)
{
(
// assigned to anything except a LocalScopeVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
) or exists(Expr midExpr, Function mid, int arg |
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
// assigned to anything except a LocalScopeVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
or
exists(Expr midExpr, Function mid, int arg |
// indirect assignment
e.(FunctionCall).getArgument(arg) = v.getAnAccess() and
mayCallFunction(e, mid) and
midExpr.getEnclosingFunction() = mid and
assignedToFieldOrGlobal(mid.getParameter(arg), midExpr)
) or (
// assigned to a field via constructor field initializer
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
)
or
// assigned to a field via constructor field initializer
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
}
from ControlFlowNode def, ReturnStmt ret
@@ -210,6 +196,4 @@ where
allocatedVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
select
def, "The memory allocated here may not be released at $@.",
ret, "this exit point"
select def, "The memory allocated here may not be released at $@.", ret, "this exit point"

View File

@@ -8,6 +8,7 @@
* security
* external/cwe/cwe-401
*/
import MemoryFreed
from Expr alloc

View File

@@ -1,6 +1,6 @@
/**
* @name Unchecked return value used as offset
* @description Using a return value as a pointer offset without checking that the value is positive
* @description Using a return value as a pointer offset without checking that the value is positive
* may lead to buffer overruns.
* @kind problem
* @id cpp/missing-negativity-test
@@ -9,59 +9,63 @@
* security
* external/cwe/cwe-823
*/
import cpp
import Negativity
class IntegralReturnValue extends FunctionCall
{
IntegralReturnValue() {
this.getType().getUnderlyingType() instanceof IntegralType
}
class IntegralReturnValue extends FunctionCall {
IntegralReturnValue() { this.getType().getUnderlyingType() instanceof IntegralType }
predicate isChecked() {
exists(ControlFlowNode def, ControlFlowNode test, Variable v |
exprDefinition(v, def, this) and
definitionReaches(def, test) and
errorSuccessor(v, test.getASuccessor()))
errorSuccessor(v, test.getASuccessor())
)
}
}
class FunctionWithNegativeReturn extends Function
{
class FunctionWithNegativeReturn extends Function {
FunctionWithNegativeReturn() {
this.getType().getUnderlyingType() instanceof IntegralType and
( exists(ReturnStmt ret |
(
exists(ReturnStmt ret |
ret.getExpr().getValue().toInt() < 0 and
ret.getEnclosingFunction() = this)
ret.getEnclosingFunction() = this
)
or
count(IntegralReturnValue val | val.getTarget() = this and val.isChecked()) * 100 /
count(IntegralReturnValue val | val.getTarget() = this) >= 80)
count(IntegralReturnValue val | val.getTarget() = this) >= 80
)
}
}
predicate dangerousUse(IntegralReturnValue val, Expr use)
{
predicate dangerousUse(IntegralReturnValue val, Expr use) {
exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val)
or
exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae |
exprDefinition(v, def, val) and
use = ae.getArrayOffset() and
not boundsChecked(v, use) and
definitionUsePair(v, def, use))
definitionUsePair(v, def, use)
)
or
(use.getParent().(AddExpr).getAnOperand() = val and
val = use and
use.getType().getUnderlyingType() instanceof PointerType)
use.getParent().(AddExpr).getAnOperand() = val and
val = use and
use.getType().getUnderlyingType() instanceof PointerType
or
exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add |
exprDefinition(v, def, val) and
definitionUsePair(v, def, use) and
add.getAnOperand() = use and
not boundsChecked(v, use) and
add.getType().getUnderlyingType() instanceof PointerType)
add.getType().getUnderlyingType() instanceof PointerType
)
}
from FunctionWithNegativeReturn f, IntegralReturnValue val, Expr dangerous
where val.getTarget() = f
and dangerousUse(val, dangerous)
select dangerous, "Dangerous use of possibly negative value (return value of '" + f.getName() + "')."
where
val.getTarget() = f and
dangerousUse(val, dangerous)
select dangerous,
"Dangerous use of possibly negative value (return value of '" + f.getName() + "')."

View File

@@ -8,9 +8,11 @@
* security
* external/cwe/cwe-476
*/
import cpp
from VariableAccess access
where maybeNull(access)
and dereferenced(access)
where
maybeNull(access) and
dereferenced(access)
select access, "Value may be null; it should be checked before dereferencing."

View File

@@ -1,111 +1,150 @@
import cpp
predicate valueOfVar(Variable v, Expr val)
{
predicate valueOfVar(Variable v, Expr val) {
val = v.getAnAccess() or
val.(AssignExpr).getLValue() = v.getAnAccess()
}
predicate boundsCheckExpr(Variable v, Expr cond)
{
exists(EQExpr eq | cond = eq and
eq.getAnOperand().getValue() = "-1" and valueOfVar(v, eq.getAnOperand()))
predicate boundsCheckExpr(Variable v, Expr cond) {
exists(EQExpr eq |
cond = eq and
eq.getAnOperand().getValue() = "-1" and
valueOfVar(v, eq.getAnOperand())
)
or
exists(NEExpr ne | cond = ne and
ne.getAnOperand().getValue() = "-1" and valueOfVar(v, ne.getAnOperand()))
exists(NEExpr ne |
cond = ne and
ne.getAnOperand().getValue() = "-1" and
valueOfVar(v, ne.getAnOperand())
)
or
exists(LTExpr lt | cond = lt and
valueOfVar(v, lt.getAnOperand()) and exists(lt.getAnOperand().getValue()))
exists(LTExpr lt |
cond = lt and
valueOfVar(v, lt.getAnOperand()) and
exists(lt.getAnOperand().getValue())
)
or
exists(LEExpr le | cond = le and
valueOfVar(v, le.getAnOperand()) and exists(le.getAnOperand().getValue()))
exists(LEExpr le |
cond = le and
valueOfVar(v, le.getAnOperand()) and
exists(le.getAnOperand().getValue())
)
or
exists(GTExpr gt | cond = gt and
valueOfVar(v, gt.getAnOperand()) and exists(gt.getAnOperand().getValue()))
exists(GTExpr gt |
cond = gt and
valueOfVar(v, gt.getAnOperand()) and
exists(gt.getAnOperand().getValue())
)
or
exists(GEExpr ge | cond = ge and
valueOfVar(v, ge.getAnOperand()) and exists(ge.getAnOperand().getValue()))
exists(GEExpr ge |
cond = ge and
valueOfVar(v, ge.getAnOperand()) and
exists(ge.getAnOperand().getValue())
)
}
predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ)
{
if node.isCondition() then
(succ = node.getATrueSuccessor() or succ = node.getAFalseSuccessor())
predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ) {
if node.isCondition()
then succ = node.getATrueSuccessor() or succ = node.getAFalseSuccessor()
else
exists(BinaryLogicalOperation binop |
binop.getAnOperand() = node and conditionalSuccessor(binop, succ))
binop.getAnOperand() = node and conditionalSuccessor(binop, succ)
)
}
predicate boundsChecked(Variable v, ControlFlowNode node)
{
predicate boundsChecked(Variable v, ControlFlowNode node) {
exists(Expr test |
boundsCheckExpr(v, test) and
conditionalSuccessor(test, node))
conditionalSuccessor(test, node)
)
or
exists(ControlFlowNode mid |
boundsChecked(v, mid) and mid = node.getAPredecessor() and not definitionBarrier(v, mid))
boundsChecked(v, mid) and mid = node.getAPredecessor() and not definitionBarrier(v, mid)
)
}
predicate errorCondition(Variable v, Expr cond)
{
exists(EQExpr eq | cond = eq and
eq.getAnOperand().getValue() = "-1" and eq.getAnOperand() = v.getAnAccess())
predicate errorCondition(Variable v, Expr cond) {
exists(EQExpr eq |
cond = eq and
eq.getAnOperand().getValue() = "-1" and
eq.getAnOperand() = v.getAnAccess()
)
or
exists(LTExpr lt | cond = lt and
lt.getLeftOperand() = v.getAnAccess() and lt.getRightOperand().getValue() = "0")
exists(LTExpr lt |
cond = lt and
lt.getLeftOperand() = v.getAnAccess() and
lt.getRightOperand().getValue() = "0"
)
or
exists(LEExpr le | cond = le and
le.getRightOperand() = v.getAnAccess() and le.getRightOperand().getValue() = "-1")
exists(LEExpr le |
cond = le and
le.getRightOperand() = v.getAnAccess() and
le.getRightOperand().getValue() = "-1"
)
or
exists(NotExpr ne | cond = ne and
successCondition(v, ne.getOperand()))
exists(NotExpr ne |
cond = ne and
successCondition(v, ne.getOperand())
)
}
predicate successCondition(Variable v, Expr cond)
{
exists(NEExpr ne | cond = ne and
ne.getAnOperand().getValue() = "-1" and ne.getAnOperand() = v.getAnAccess())
predicate successCondition(Variable v, Expr cond) {
exists(NEExpr ne |
cond = ne and
ne.getAnOperand().getValue() = "-1" and
ne.getAnOperand() = v.getAnAccess()
)
or
exists(GEExpr ge | cond = ge and
ge.getLeftOperand() = v.getAnAccess() and ge.getRightOperand().getValue() = "0")
exists(GEExpr ge |
cond = ge and
ge.getLeftOperand() = v.getAnAccess() and
ge.getRightOperand().getValue() = "0"
)
or
exists(GTExpr gt | cond = gt and
gt.getRightOperand() = v.getAnAccess() and gt.getRightOperand().getValue() = "-1")
exists(GTExpr gt |
cond = gt and
gt.getRightOperand() = v.getAnAccess() and
gt.getRightOperand().getValue() = "-1"
)
or
exists(NotExpr ne | cond = ne and
errorCondition(v, ne.getOperand()))
exists(NotExpr ne |
cond = ne and
errorCondition(v, ne.getOperand())
)
}
predicate errorSuccessor(Variable v, ControlFlowNode n)
{
predicate errorSuccessor(Variable v, ControlFlowNode n) {
exists(Expr cond |
(errorCondition(v, cond) and n = cond.getATrueSuccessor()) or
(successCondition(v, cond) and n = cond.getAFalseSuccessor()))
errorCondition(v, cond) and n = cond.getATrueSuccessor()
or
successCondition(v, cond) and n = cond.getAFalseSuccessor()
)
}
predicate successSuccessor(Variable v, ControlFlowNode n)
{
predicate successSuccessor(Variable v, ControlFlowNode n) {
exists(Expr cond |
(successCondition(v, cond) and n = cond.getATrueSuccessor()) or
(errorCondition(v, cond) and n = cond.getAFalseSuccessor()))
successCondition(v, cond) and n = cond.getATrueSuccessor()
or
errorCondition(v, cond) and n = cond.getAFalseSuccessor()
)
}
predicate checkedError(Variable v, ControlFlowNode n)
{
predicate checkedError(Variable v, ControlFlowNode n) {
errorSuccessor(v, n)
or
exists(ControlFlowNode mid |
checkedError(v, mid) and
n = mid.getASuccessor() and
not definitionBarrier(v, mid))
not definitionBarrier(v, mid)
)
}
predicate checkedSuccess(Variable v, ControlFlowNode n)
{
predicate checkedSuccess(Variable v, ControlFlowNode n) {
successSuccessor(v, n)
or
exists(ControlFlowNode mid |
checkedSuccess(v, mid) and
n = mid.getASuccessor() and
not definitionBarrier(v, mid))
not definitionBarrier(v, mid)
)
}

View File

@@ -7,12 +7,11 @@
* @id cpp/new-array-delete-mismatch
* @tags reliability
*/
import NewDelete
from Expr alloc, Expr free, Expr freed
where
allocReaches(freed, alloc, "new[]") and
freeExprOrIndirect(free, freed, "delete")
select
free, "This memory may have been allocated with '$@', not 'new'.",
alloc, "new[]"
select free, "This memory may have been allocated with '$@', not 'new'.", alloc, "new[]"

View File

@@ -1,6 +1,7 @@
/**
* Provides predicates for associating new/malloc calls with delete/free.
*/
import cpp
import semmle.code.cpp.controlflow.SSA
import semmle.code.cpp.dataflow.DataFlow
@@ -12,24 +13,20 @@ import semmle.code.cpp.dataflow.DataFlow
predicate allocExpr(Expr alloc, string kind) {
isAllocationExpr(alloc) and
(
(
alloc instanceof FunctionCall and
kind = "malloc"
) or (
alloc instanceof NewExpr and
kind = "new" and
// exclude placement new and custom overloads as they
// may not conform to assumptions
not alloc.(NewExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
) or (
alloc instanceof NewArrayExpr and
kind = "new[]" and
// exclude placement new and custom overloads as they
// may not conform to assumptions
not alloc.(NewArrayExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
)
alloc instanceof FunctionCall and
kind = "malloc"
or
alloc instanceof NewExpr and
kind = "new" and
// exclude placement new and custom overloads as they
// may not conform to assumptions
not alloc.(NewExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
or
alloc instanceof NewArrayExpr and
kind = "new[]" and
// exclude placement new and custom overloads as they
// may not conform to assumptions
not alloc.(NewArrayExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
)
}
@@ -40,13 +37,14 @@ predicate allocExpr(Expr alloc, string kind) {
*/
predicate allocExprOrIndirect(Expr alloc, string kind) {
// direct alloc
allocExpr(alloc, kind) or
allocExpr(alloc, kind)
or
exists(ReturnStmt rtn |
// indirect alloc via function call
alloc.(FunctionCall).getTarget() = rtn.getEnclosingFunction() and
(
allocExprOrIndirect(rtn.getExpr(), kind) or
allocExprOrIndirect(rtn.getExpr(), kind)
or
exists(Expr e |
allocExprOrIndirect(e, kind) and
DataFlow::localFlow(DataFlow::exprNode(e), DataFlow::exprNode(rtn.getExpr()))
@@ -59,7 +57,8 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
* Holds if `v` is a non-local variable which is assigned with allocations of
* type `kind`.
*/
private pragma[nomagic] predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
pragma[nomagic]
private predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
exists(Expr mid |
not v instanceof LocalScopeVariable and
v.getAnAssignedValue() = mid and
@@ -73,18 +72,20 @@ private pragma[nomagic] predicate allocReachesVariable(Variable v, Expr alloc, s
* string describing the type of that allocation.
*/
private predicate allocReaches0(Expr e, Expr alloc, string kind) {
(
// alloc
allocExprOrIndirect(alloc, kind) and
e = alloc
) or exists(SsaDefinition def, LocalScopeVariable v |
// alloc
allocExprOrIndirect(alloc, kind) and
e = alloc
or
exists(SsaDefinition def, LocalScopeVariable v |
// alloc via SSA
allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and
e = def.getAUse(v)
) or exists(Variable v |
)
or
exists(Variable v |
// alloc via a global
allocReachesVariable(v, alloc, kind) and
strictcount(VariableAccess va | va.getTarget() = v) <= 50 and // avoid very expensive cases
strictcount(VariableAccess va | va.getTarget() = v) <= 50 and // avoid very expensive cases
e.(VariableAccess).getTarget() = v
)
}
@@ -97,7 +98,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) {
predicate allocReaches(Expr e, Expr alloc, string kind) {
allocReaches0(e, alloc, kind) and
not exists(string k2 |
allocReaches0(e, _, k2) and
allocReaches0(e, _, k2) and
kind != k2
)
}
@@ -108,16 +109,14 @@ predicate allocReaches(Expr e, Expr alloc, string kind) {
* describing the type of that free or delete.
*/
predicate freeExpr(Expr free, Expr freed, string kind) {
(
freeCall(free, freed) and
kind = "free"
) or (
free.(DeleteExpr).getExpr() = freed and
kind = "delete"
) or (
free.(DeleteArrayExpr).getExpr() = freed and
kind = "delete[]"
)
freeCall(free, freed) and
kind = "free"
or
free.(DeleteExpr).getExpr() = freed and
kind = "delete"
or
free.(DeleteArrayExpr).getExpr() = freed and
kind = "delete[]"
}
/**
@@ -128,8 +127,8 @@ predicate freeExpr(Expr free, Expr freed, string kind) {
*/
predicate freeExprOrIndirect(Expr free, Expr freed, string kind) {
// direct free
freeExpr(free, freed, kind) or
freeExpr(free, freed, kind)
or
// indirect free via function call
exists(Expr internalFree, Expr internalFreed, int arg |
freeExprOrIndirect(internalFree, internalFreed, kind) and

View File

@@ -7,12 +7,11 @@
* @id cpp/new-delete-array-mismatch
* @tags reliability
*/
import NewDelete
from Expr alloc, Expr free, Expr freed
where
allocReaches(freed, alloc, "new") and
freeExprOrIndirect(free, freed, "delete[]")
select
free, "This memory may have been allocated with '$@', not 'new[]'.",
alloc, "new"
select free, "This memory may have been allocated with '$@', not 'new[]'.", alloc, "new"

View File

@@ -9,6 +9,7 @@
* security
* external/cwe/cwe-401
*/
import NewDelete
/**
@@ -16,22 +17,22 @@ import NewDelete
* types of allocation and free.
*/
predicate correspondingKinds(string allocKind, string freeKind) {
(
allocKind = "malloc" and
freeKind = "free"
) or (
allocKind = "new" and
freeKind = "delete"
)
allocKind = "malloc" and
freeKind = "free"
or
allocKind = "new" and
freeKind = "delete"
}
from
Expr alloc, string allocKind, string allocKindSimple,
Expr free, Expr freed, string freeKind, string freeKindSimple
Expr alloc, string allocKind, string allocKindSimple, Expr free, Expr freed, string freeKind,
string freeKindSimple
where
allocReaches(freed, alloc, allocKind) and
freeExprOrIndirect(free, freed, freeKind) and
allocKindSimple = allocKind.replaceAll("[]", "") and
freeKindSimple = freeKind.replaceAll("[]", "") and
not correspondingKinds(allocKindSimple, freeKindSimple)
select free, "There is a " + allocKindSimple + "/" + freeKindSimple + " mismatch between this " + freeKind + " and the corresponding $@.", alloc, allocKind
select free,
"There is a " + allocKindSimple + "/" + freeKindSimple + " mismatch between this " + freeKind +
" and the corresponding $@.", alloc, allocKind

View File

@@ -11,7 +11,6 @@
import cpp
// See also InitialisationNotRun.ql and GlobalUseBeforeInit.ql
/**
* Holds if `s` defines variable `v` (conservative).
*/

View File

@@ -9,39 +9,51 @@
* external/cwe/cwe-131
* external/cwe/cwe-120
*/
import cpp
class MallocCall extends FunctionCall
{
class MallocCall extends FunctionCall {
MallocCall() {
this.getTarget().hasQualifiedName("malloc") or
this.getTarget().hasQualifiedName("std::malloc")
this.getTarget().hasQualifiedName("malloc") or
this.getTarget().hasQualifiedName("std::malloc")
}
Expr getAllocatedSize() {
if this.getArgument(0) instanceof VariableAccess then
if this.getArgument(0) instanceof VariableAccess
then
exists(LocalScopeVariable v, ControlFlowNode def |
definitionUsePair(v, def, this.getArgument(0)) and
exprDefinition(v, def, result))
else
result = this.getArgument(0)
exprDefinition(v, def, result)
)
else result = this.getArgument(0)
}
}
predicate spaceProblem(FunctionCall append, string msg)
{
predicate terminationProblem(MallocCall malloc, string msg) {
malloc.getAllocatedSize() instanceof StrlenCall and
msg = "This allocation does not include space to null-terminate the string."
}
predicate spaceProblem(FunctionCall append, string msg) {
exists(MallocCall malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer |
add.getAChild() = strlen
and exists(add.getAChild().getValue())
and malloc.getAllocatedSize() = add
and buffer.getAnAccess() = strlen.getStringExpr()
and (insert.getTarget().hasQualifiedName("strcpy") or insert.getTarget().hasQualifiedName("strncpy"))
and (append.getTarget().hasQualifiedName("strcat") or append.getTarget().hasQualifiedName("strncat"))
and malloc.getASuccessor+() = insert
and insert.getArgument(1) = buffer.getAnAccess()
and insert.getASuccessor+() = append
and msg = "This buffer only contains enough room for '" + buffer.getName() +
"' (copied on line " + insert.getLocation().getStartLine().toString() + ")")
add.getAChild() = strlen and
exists(add.getAChild().getValue()) and
malloc.getAllocatedSize() = add and
buffer.getAnAccess() = strlen.getStringExpr() and
(
insert.getTarget().hasQualifiedName("strcpy") or
insert.getTarget().hasQualifiedName("strncpy")
) and
(
append.getTarget().hasQualifiedName("strcat") or
append.getTarget().hasQualifiedName("strncat")
) and
malloc.getASuccessor+() = insert and
insert.getArgument(1) = buffer.getAnAccess() and
insert.getASuccessor+() = append and
msg = "This buffer only contains enough room for '" + buffer.getName() + "' (copied on line " +
insert.getLocation().getStartLine().toString() + ")"
)
}
from Expr problem, string msg

View File

@@ -11,6 +11,7 @@
* external/cwe/cwe-119
* external/cwe/cwe-131
*/
import cpp
import semmle.code.cpp.security.TaintTracking
@@ -21,30 +22,34 @@ import semmle.code.cpp.security.TaintTracking
* memcpy(dest, src, sizeof(src));
* ```
*/
predicate sourceSized(FunctionCall fc, Expr src)
{
predicate sourceSized(FunctionCall fc, Expr src) {
exists(string name |
(name = "strncpy" or name = "strncat" or name = "memcpy" or name = "memmove") and
fc.getTarget().hasQualifiedName(name))
and
fc.getTarget().hasQualifiedName(name)
) and
exists(Expr dest, Expr size, Variable v |
fc.getArgument(0) = dest and fc.getArgument(1) = src and fc.getArgument(2) = size and
src = v.getAnAccess() and size.getAChild+() = v.getAnAccess() and
fc.getArgument(0) = dest and
fc.getArgument(1) = src and
fc.getArgument(2) = size and
src = v.getAnAccess() and
size.getAChild+() = v.getAnAccess() and
// exception: `dest` is also referenced in the size argument
not exists(Variable other |
dest = other.getAnAccess() and size.getAChild+() = other.getAnAccess())
and
dest = other.getAnAccess() and size.getAChild+() = other.getAnAccess()
) and
// exception: `src` and `dest` are both arrays of the same type and size
not exists(ArrayType srctype, ArrayType desttype |
dest.getType().getUnderlyingType() = desttype and
src.getType().getUnderlyingType() = srctype and
desttype.getBaseType().getUnderlyingType() = srctype.getBaseType().getUnderlyingType() and
desttype.getArraySize() = srctype.getArraySize()))
desttype.getArraySize() = srctype.getArraySize()
)
)
}
from FunctionCall fc, Expr vuln, Expr taintSource
where sourceSized(fc, vuln)
and tainted(taintSource, vuln)
select fc, "To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size."
where
sourceSized(fc, vuln) and
tainted(taintSource, vuln)
select fc,
"To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size."

View File

@@ -11,31 +11,28 @@
* external/cwe/cwe-119
* external/cwe/cwe-131
*/
import cpp
import semmle.code.cpp.commons.Buffer
import LoopBounds
private predicate staticBufferBase(VariableAccess access, Variable v)
{
private predicate staticBufferBase(VariableAccess access, Variable v) {
v.getType().(ArrayType).getBaseType() instanceof CharType and
access = v.getAnAccess() and
not memberMayBeVarSize(_, v)
}
predicate staticBuffer(VariableAccess access, Variable v, int size)
{
predicate staticBuffer(VariableAccess access, Variable v, int size) {
staticBufferBase(access, v) and
size = getBufferSize(access, _)
}
class BufferAccess extends ArrayExpr
{
class BufferAccess extends ArrayExpr {
BufferAccess() {
exists(int size |
staticBuffer(this.getArrayBase(), _, size) and
size != 0
) and
// exclude accesses in macro implementation of `strcmp`,
// which are carefully controlled but can look dangerous.
not exists(Macro m |
@@ -44,53 +41,57 @@ class BufferAccess extends ArrayExpr
)
}
int bufferSize() {
staticBuffer(this.getArrayBase(), _, result)
}
int bufferSize() { staticBuffer(this.getArrayBase(), _, result) }
Variable buffer() {
result.getAnAccess() = this.getArrayBase()
}
Variable buffer() { result.getAnAccess() = this.getArrayBase() }
}
predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg)
{
predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
exists(ClassicForLoop loop |
loop.getStmt().getAChild*() = bufaccess.getEnclosingStmt() and
loop.limit() >= bufaccess.bufferSize() and
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
msg = "Potential buffer-overflow: counter '" + loop.counter().toString()
+ "' <= " + loop.limit().toString() + " but '" + bufaccess.buffer().getName()
+ "' has " + bufaccess.bufferSize().toString() + " elements.")
msg = "Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
bufaccess.bufferSize().toString() + " elements."
)
}
predicate bufferAndSizeFunction(Function f, int buf, int size)
{
(f.hasQualifiedName("read") and buf = 1 and size = 2) or
(f.hasQualifiedName("fgets") and buf = 0 and size = 1) or
(f.hasQualifiedName("strncpy") and buf = 0 and size = 2) or
(f.hasQualifiedName("strncat") and buf = 0 and size = 2) or
(f.hasQualifiedName("memcpy") and buf = 0 and size = 2) or
(f.hasQualifiedName("memmove") and buf = 0 and size = 2) or
(f.hasQualifiedName("snprintf") and buf = 0 and size = 1) or
(f.hasQualifiedName("vsnprintf") and buf = 0 and size = 1)
predicate bufferAndSizeFunction(Function f, int buf, int size) {
f.hasQualifiedName("read") and buf = 1 and size = 2
or
f.hasQualifiedName("fgets") and buf = 0 and size = 1
or
f.hasQualifiedName("strncpy") and buf = 0 and size = 2
or
f.hasQualifiedName("strncat") and buf = 0 and size = 2
or
f.hasQualifiedName("memcpy") and buf = 0 and size = 2
or
f.hasQualifiedName("memmove") and buf = 0 and size = 2
or
f.hasQualifiedName("snprintf") and buf = 0 and size = 1
or
f.hasQualifiedName("vsnprintf") and buf = 0 and size = 1
}
class CallWithBufferSize extends FunctionCall
{
class CallWithBufferSize extends FunctionCall {
CallWithBufferSize() { bufferAndSizeFunction(this.getTarget(), _, _) }
Expr buffer() {
exists(int i |
bufferAndSizeFunction(this.getTarget(), i, _) and
result = this.getArgument(i)
)
}
Expr statedSizeExpr() {
exists(int i |
bufferAndSizeFunction(this.getTarget(), _, i) and
result = this.getArgument(i)
)
}
int statedSizeValue() {
exists(Expr statedSizeSrc |
DataFlow::localFlow(DataFlow::exprNode(statedSizeSrc), DataFlow::exprNode(statedSizeExpr())) and
@@ -105,24 +106,29 @@ predicate wrongBufferSize(Expr error, string msg) {
statedSize = min(call.statedSizeValue()) and
statedSize > bufsize and
error = call.statedSizeExpr() and
msg = "Potential buffer-overflow: '" + buf.getName() +
"' has size " + bufsize.toString() + " not " + statedSize + ".")
msg = "Potential buffer-overflow: '" + buf.getName() + "' has size " + bufsize.toString() +
" not " + statedSize + "."
)
}
predicate outOfBounds(BufferAccess bufaccess, string msg)
{
predicate outOfBounds(BufferAccess bufaccess, string msg) {
exists(int size, int access, string buf |
buf = bufaccess.buffer().getName() and
bufaccess.bufferSize() = size and
bufaccess.getArrayOffset().getValue().toInt() = access and
( access > size or
(access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand()))) and
msg = "Potential buffer-overflow: '" + buf + "' has size " + size.toString() +
" but '" + buf + "[" + access.toString() + "]' is accessed here.")
(
access > size
or
access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand())
) and
msg = "Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf +
"[" + access.toString() + "]' is accessed here."
)
}
from Element error, string msg
where overflowOffsetInLoop(error, msg)
or wrongBufferSize(error, msg)
or outOfBounds(error, msg)
where
overflowOffsetInLoop(error, msg) or
wrongBufferSize(error, msg) or
outOfBounds(error, msg)
select error, msg

View File

@@ -8,25 +8,25 @@
* security
* external/cwe/cwe-562
*/
import semmle.code.cpp.pointsto.PointsTo
class ReturnPointsToExpr extends PointsToExpr
{
class ReturnPointsToExpr extends PointsToExpr {
override predicate interesting() {
exists(ReturnStmt ret | ret.getExpr().getFullyConverted() = this)
and pointerValue(this)
exists(ReturnStmt ret | ret.getExpr().getFullyConverted() = this) and
pointerValue(this)
}
ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this }
}
from ReturnPointsToExpr ret, LocalVariable local, float confidence
where ret.pointsTo() = local
and ret.getReturnStmt().getEnclosingFunction() = local.getFunction()
and not(local.isStatic())
and confidence = ret.confidence()
and confidence > 0.01
where
ret.pointsTo() = local and
ret.getReturnStmt().getEnclosingFunction() = local.getFunction() and
not local.isStatic() and
confidence = ret.confidence() and
confidence > 0.01
select ret,
"This may return a pointer to '" + local.getName() +
"' (declared on line " + local.getADeclarationLocation().getStartLine().toString() +
"), which is stack allocated."
"This may return a pointer to '" + local.getName() + "' (declared on line " +
local.getADeclarationLocation().getStartLine().toString() + "), which is stack allocated."

View File

@@ -9,35 +9,35 @@
* correctness
* external/cwe/cwe-252
*/
import cpp
predicate unused(Expr e)
{
e instanceof ExprInVoidContext
}
predicate unused(Expr e) { e instanceof ExprInVoidContext }
predicate important(Function f, string message)
{
predicate important(Function f, string message) {
message = "the result of this function must always be checked." and
getOptions().alwaysCheckReturnValue(f)
}
// statistically dubious ignored return values
predicate dubious(Function f, string message)
{
predicate dubious(Function f, string message) {
not important(f, _) and
exists(Options opts, int used, int total, int percentage |
used = count(FunctionCall fc | fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc) and not unused(fc)) and
used = count(FunctionCall fc |
fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc) and not unused(fc)
) and
total = count(FunctionCall fc | fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc)) and
used != total and
percentage = used * 100 / total and
percentage >= 90 and
message = percentage.toString() + "% of calls to this function have their result used.")
message = percentage.toString() + "% of calls to this function have their result used."
)
}
from FunctionCall unused, string message
where unused(unused)
and not exists(Options opts | opts.okToIgnoreReturnValue(unused))
and (important(unused.getTarget(), message) or dubious(unused.getTarget(), message))
and not unused.getTarget().getName().matches("operator%") // exclude user defined operators
where
unused(unused) and
not exists(Options opts | opts.okToIgnoreReturnValue(unused)) and
(important(unused.getTarget(), message) or dubious(unused.getTarget(), message)) and
not unused.getTarget().getName().matches("operator%") // exclude user defined operators
select unused, "Result of call to " + unused.getTarget().getName() + " is ignored; " + message

View File

@@ -25,20 +25,14 @@ class Allocation extends FunctionCall {
string getName() { result = this.getTarget().getQualifiedName() }
int getSize() {
(
this.getName() = "malloc" and
this.getArgument(0).getValue().toInt() = result
)
this.getName() = "malloc" and
this.getArgument(0).getValue().toInt() = result
or
(
this.getName() = "realloc" and
this.getArgument(1).getValue().toInt() = result
)
this.getName() = "realloc" and
this.getArgument(1).getValue().toInt() = result
or
(
this.getName() = "calloc" and
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
)
this.getName() = "calloc" and
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
}
}

View File

@@ -25,20 +25,14 @@ class Allocation extends FunctionCall {
string getName() { result = this.getTarget().getQualifiedName() }
int getSize() {
(
this.getName() = "malloc" and
this.getArgument(0).getValue().toInt() = result
)
this.getName() = "malloc" and
this.getArgument(0).getValue().toInt() = result
or
(
this.getName() = "realloc" and
this.getArgument(1).getValue().toInt() = result
)
this.getName() = "realloc" and
this.getArgument(1).getValue().toInt() = result
or
(
this.getName() = "calloc" and
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
)
this.getName() = "calloc" and
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
}
}

View File

@@ -7,6 +7,7 @@
* @tags maintainability
* external/cwe/cwe-563
*/
import cpp
// Sometimes it is useful to have a class which is instantiated (on the stack)
@@ -15,22 +16,19 @@ import cpp
// sometimes locking is done this way.
//
// Obviously, such instantiations should not be treated as unused values.
class ScopeUtilityClass extends Class
{
Call getAUse()
{
result = this.getAConstructor().getACallToThisFunction()
}
class ScopeUtilityClass extends Class {
Call getAUse() { result = this.getAConstructor().getACallToThisFunction() }
}
from LocalScopeVariable v, ControlFlowNode def
where definition(v, def)
and not definitionUsePair(v, def, _)
and not v.isStatic()
and not v.getAnAccess().isAddressOfAccess()
where
definition(v, def) and
not definitionUsePair(v, def, _) and
not v.isStatic() and
not v.getAnAccess().isAddressOfAccess() and
// parameter initializers are not in the call-graph at the moment
and not v.(Parameter).getInitializer().getExpr() = def
and not v.getType().getUnderlyingType() instanceof ReferenceType
and not exists(ScopeUtilityClass util | def = util.getAUse())
and not def.isInMacroExpansion()
not v.(Parameter).getInitializer().getExpr() = def and
not v.getType().getUnderlyingType() instanceof ReferenceType and
not exists(ScopeUtilityClass util | def = util.getAUse()) and
not def.isInMacroExpansion()
select def, "Variable '" + v.getName() + "' is assigned a value that is never used"

View File

@@ -8,17 +8,16 @@
* security
* external/cwe/cwe-416
*/
import cpp
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
/** `e` is an expression that frees the memory pointed to by `v`. */
predicate isFreeExpr(Expr e, LocalScopeVariable v) {
exists(VariableAccess va |
va.getTarget() = v |
exists(FunctionCall fc |
fc = e |
fc.getTarget().hasQualifiedName("free")
and va = fc.getArgument(0)
exists(VariableAccess va | va.getTarget() = v |
exists(FunctionCall fc | fc = e |
fc.getTarget().hasQualifiedName("free") and
va = fc.getArgument(0)
)
or
e.(DeleteExpr).getExpr() = va
@@ -41,25 +40,18 @@ predicate isDerefExpr(Expr e, LocalScopeVariable v) {
* parameter.
*/
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, LocalScopeVariable v) {
v.getAnAccess() = va
and
va = c.getAnArgumentSubExpr(i)
and
not c.passesByReference(i, va)
and
v.getAnAccess() = va and
va = c.getAnArgumentSubExpr(i) and
not c.passesByReference(i, va) and
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
}
class UseAfterFreeReachability extends LocalScopeVariableReachability {
UseAfterFreeReachability() { this = "UseAfterFree" }
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
isFreeExpr(node, v)
}
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { isFreeExpr(node, v) }
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
isDerefExpr(node, v)
}
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { isDerefExpr(node, v) }
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
definitionBarrier(v, node) or
@@ -69,6 +61,5 @@ class UseAfterFreeReachability extends LocalScopeVariableReachability {
from UseAfterFreeReachability r, LocalScopeVariable v, Expr free, Expr e
where r.reaches(free, v, e)
select e,
"Memory pointed to by '" + v.getName().toString() +
"' may have been previously freed $@", free, "here"
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
free, "here"