mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
C++: Use StackVariableReachability
This library is a drop-in replacement for `LocalScopeVariableReachability`, so no changes are expected.
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import FileClosed
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
/**
|
||||
* Extend the NullValue class used by Nullness.qll to include simple -1 as a 'null' value
|
||||
@@ -68,18 +68,18 @@ predicate fcloseCallOrIndirect(FunctionCall fc, Variable v) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
predicate fopenDefinition(StackVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr))
|
||||
}
|
||||
|
||||
class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
class FOpenVariableReachability extends StackVariableReachabilityWithReassignment {
|
||||
FOpenVariableReachability() { this = "FOpenVariableReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
fopenDefinition(v, node)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
// node may be used in fopenReaches
|
||||
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
|
||||
fcloseCallOrIndirect(node, v) or
|
||||
@@ -88,15 +88,13 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
definitionBarrier(v, node)
|
||||
}
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The value from fopen at `def` is still held in Variable `v` upon entering `node`.
|
||||
*/
|
||||
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
predicate fopenVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(FOpenVariableReachability r |
|
||||
// reachability
|
||||
r.reachesTo(def, _, node, v)
|
||||
@@ -107,25 +105,23 @@ predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, Contro
|
||||
)
|
||||
}
|
||||
|
||||
class FOpenReachability extends LocalScopeVariableReachabilityExt {
|
||||
class FOpenReachability extends StackVariableReachabilityExt {
|
||||
FOpenReachability() { this = "FOpenReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
fopenDefinition(v, node)
|
||||
}
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { fopenDefinition(v, node) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
|
||||
) {
|
||||
isSource(source, v) and
|
||||
next = node.getASuccessor() and
|
||||
// the file (stored in any variable `v0`) opened at `source` is closed or
|
||||
// assigned to a global at node, or NULL checked on the edge node -> next.
|
||||
exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) |
|
||||
exists(StackVariable v0 | fopenVariableReaches(v0, source, node) |
|
||||
node.(AnalysedExpr).getNullSuccessor(v0) = next or
|
||||
fcloseCallOrIndirect(node, v0) or
|
||||
assignedToFieldOrGlobal(v0, node)
|
||||
@@ -142,11 +138,11 @@ predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(FOpenReachability r | r.reaches(def, _, node))
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
|
||||
// assigned to anything except a StackVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
|
||||
or
|
||||
exists(Expr midExpr, Function mid, int arg |
|
||||
// indirect assignment
|
||||
@@ -163,7 +159,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
from ControlFlowNode def, ReturnStmt ret
|
||||
where
|
||||
fopenReaches(def, ret) and
|
||||
not exists(LocalScopeVariable v |
|
||||
not exists(StackVariable v |
|
||||
fopenVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import MemoryFreed
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
/**
|
||||
* 'call' is either a direct call to f, or a possible call to f
|
||||
@@ -97,18 +97,18 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
predicate allocationDefinition(StackVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr))
|
||||
}
|
||||
|
||||
class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
class AllocVariableReachability extends StackVariableReachabilityWithReassignment {
|
||||
AllocVariableReachability() { this = "AllocVariableReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
allocationDefinition(v, node)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
// node may be used in allocationReaches
|
||||
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
|
||||
freeCallOrIndirect(node, v) or
|
||||
@@ -117,15 +117,13 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
definitionBarrier(v, node)
|
||||
}
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The value from allocation `def` is still held in Variable `v` upon entering `node`.
|
||||
*/
|
||||
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
predicate allocatedVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(AllocVariableReachability r |
|
||||
// reachability
|
||||
r.reachesTo(def, _, node, v)
|
||||
@@ -136,25 +134,25 @@ predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, Co
|
||||
)
|
||||
}
|
||||
|
||||
class AllocReachability extends LocalScopeVariableReachabilityExt {
|
||||
class AllocReachability extends StackVariableReachabilityExt {
|
||||
AllocReachability() { this = "AllocReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) {
|
||||
allocationDefinition(v, node)
|
||||
}
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
|
||||
) {
|
||||
isSource(source, v) and
|
||||
next = node.getASuccessor() and
|
||||
// the memory (stored in any variable `v0`) allocated at `source` is freed or
|
||||
// assigned to a global at node, or NULL checked on the edge node -> next.
|
||||
exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) |
|
||||
exists(StackVariable v0 | allocatedVariableReaches(v0, source, node) |
|
||||
node.(AnalysedExpr).getNullSuccessor(v0) = next or
|
||||
freeCallOrIndirect(node, v0) or
|
||||
assignedToFieldOrGlobal(v0, node)
|
||||
@@ -171,11 +169,11 @@ predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(AllocReachability r | r.reaches(def, _, node))
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
|
||||
// assigned to anything except a StackVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
|
||||
or
|
||||
exists(Expr midExpr, Function mid, int arg |
|
||||
// indirect assignment
|
||||
@@ -192,7 +190,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
from ControlFlowNode def, ReturnStmt ret
|
||||
where
|
||||
allocationReaches(def, ret) and
|
||||
not exists(LocalScopeVariable v |
|
||||
not exists(StackVariable v |
|
||||
allocatedVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
/** `e` is an expression that frees the memory pointed to by `v`. */
|
||||
predicate isFreeExpr(Expr e, LocalScopeVariable v) {
|
||||
predicate isFreeExpr(Expr e, StackVariable v) {
|
||||
exists(VariableAccess va | va.getTarget() = v |
|
||||
exists(FunctionCall fc | fc = e |
|
||||
fc.getTarget().hasGlobalOrStdName("free") and
|
||||
@@ -27,7 +27,7 @@ predicate isFreeExpr(Expr e, LocalScopeVariable v) {
|
||||
}
|
||||
|
||||
/** `e` is an expression that (may) dereference `v`. */
|
||||
predicate isDerefExpr(Expr e, LocalScopeVariable v) {
|
||||
predicate isDerefExpr(Expr e, StackVariable v) {
|
||||
v.getAnAccess() = e and dereferenced(e)
|
||||
or
|
||||
isDerefByCallExpr(_, _, e, v)
|
||||
@@ -39,27 +39,27 @@ predicate isDerefExpr(Expr e, LocalScopeVariable v) {
|
||||
* or a source code function that dereferences the relevant
|
||||
* parameter.
|
||||
*/
|
||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, LocalScopeVariable v) {
|
||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
|
||||
v.getAnAccess() = va and
|
||||
va = c.getAnArgumentSubExpr(i) and
|
||||
not c.passesByReference(i, va) and
|
||||
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
|
||||
}
|
||||
|
||||
class UseAfterFreeReachability extends LocalScopeVariableReachability {
|
||||
class UseAfterFreeReachability extends StackVariableReachability {
|
||||
UseAfterFreeReachability() { this = "UseAfterFree" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { isFreeExpr(node, v) }
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { isDerefExpr(node, v) }
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
definitionBarrier(v, node) or
|
||||
isFreeExpr(node, v)
|
||||
}
|
||||
}
|
||||
|
||||
from UseAfterFreeReachability r, LocalScopeVariable v, Expr free, Expr e
|
||||
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
|
||||
where r.reaches(free, v, e)
|
||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
|
||||
free, "here"
|
||||
|
||||
@@ -12,24 +12,24 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
class UndefReachability extends LocalScopeVariableReachability {
|
||||
class UndefReachability extends StackVariableReachability {
|
||||
UndefReachability() { this = "UndefReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) {
|
||||
candidateVariable(v) and
|
||||
node = v.getParentScope() and
|
||||
not v instanceof Parameter and
|
||||
not v.hasInitializer()
|
||||
}
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
candidateVariable(v) and
|
||||
node = v.getAnAccess()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
node.(AssignExpr).getLValue() = v.getAnAccess()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
import semmle.code.cpp.commons.NullTermination
|
||||
|
||||
/**
|
||||
@@ -22,10 +22,10 @@ DeclStmt declWithNoInit(LocalVariable v) {
|
||||
not exists(v.getInitializer())
|
||||
}
|
||||
|
||||
class ImproperNullTerminationReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
class ImproperNullTerminationReachability extends StackVariableReachabilityWithReassignment {
|
||||
ImproperNullTerminationReachability() { this = "ImproperNullTerminationReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
node = declWithNoInit(v)
|
||||
or
|
||||
exists(Call c, VariableAccess va |
|
||||
@@ -36,12 +36,12 @@ class ImproperNullTerminationReachability extends LocalScopeVariableReachability
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
node.(VariableAccess).getTarget() = v and
|
||||
variableMustBeNullTerminated(node)
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
exprDefinition(v, node, _) or
|
||||
mayAddNullTerminator(node, v.getAnAccess()) or
|
||||
isSinkActual(node, v) // only report first use
|
||||
|
||||
@@ -924,7 +924,7 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
|
||||
/*
|
||||
* Use primitive basic blocks in reachability analysis for better performance.
|
||||
* This is similar to the pattern used in e.g. `DefinitionsAndUses` and
|
||||
* `LocalScopeVariableReachability`.
|
||||
* `StackVariableReachability`.
|
||||
*/
|
||||
|
||||
exists(PrimitiveBasicBlock bb1, int pos1 | bb1.getNode(pos1) = valueOrDef |
|
||||
|
||||
Reference in New Issue
Block a user