Merge remote-tracking branch 'upstream/master' into MissingEnumCaseInSwitch-perf

This commit is contained in:
Jonas Jensen
2020-02-28 09:57:29 +01:00
2174 changed files with 127511 additions and 58212 deletions

View File

@@ -10,12 +10,25 @@ import cpp
/**
* An alert suppression comment.
*/
class SuppressionComment extends CppStyleComment {
class SuppressionComment extends Comment {
string annotation;
string text;
SuppressionComment() {
text = getContents().suffix(2) and
(
this instanceof CppStyleComment and
// strip the beginning slashes
text = getContents().suffix(2)
or
this instanceof CStyleComment and
// strip both the beginning /* and the end */ the comment
exists(string text0 |
text0 = getContents().suffix(2) and
text = text0.prefix(text0.length() - 2)
) and
// The /* */ comment must be a single-line comment
not text.matches("%\n%")
) and
(
// match `lgtm[...]` anywhere in the comment
annotation = text.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _)

View File

@@ -3,7 +3,7 @@
* @description A function that uses more functions and variables from another file than functions and variables from its own file. This function might be better placed in the other file, to avoid exposing internals of the file it depends on.
* @kind problem
* @problem.severity recommendation
* @precision high
* @precision medium
* @id cpp/feature-envy
* @tags maintainability
* modularity
@@ -25,7 +25,8 @@ predicate functionUsesFunction(Function source, Function f, File target) {
}
predicate dependencyCount(Function source, File target, int res) {
res = strictcount(Declaration d |
res =
strictcount(Declaration d |
functionUsesVariable(source, d, target) or
functionUsesFunction(source, d, target)
)

View File

@@ -38,14 +38,16 @@ where
n = count(Function f | f.fromSource()).toString()
or
l = "Number of Lines Of Code" and
n = sum(File f, int toSum |
n =
sum(File f, int toSum |
f.fromSource() and toSum = f.getMetrics().getNumberOfLinesOfCode()
|
toSum
).toString()
or
l = "Self-Containedness" and
n = (
n =
(
100 * sum(Class c | c.fromSource() | c.getMetrics().getEfferentSourceCoupling()) /
sum(Class c | c.fromSource() | c.getMetrics().getEfferentCoupling())
).toString() + "%"

View File

@@ -3,7 +3,7 @@
* @description Two files share too much information about each other (accessing many operations or variables in both directions). It would be better to invert some of the dependencies to reduce the coupling between the two files.
* @kind problem
* @problem.severity recommendation
* @precision high
* @precision medium
* @id cpp/file-intimacy
* @tags maintainability
* modularity

View File

@@ -3,7 +3,7 @@
* @description Finds classes with many fields; they could probably be refactored by breaking them down into smaller classes, and using composition.
* @kind problem
* @problem.severity recommendation
* @precision high
* @precision medium
* @id cpp/class-many-fields
* @tags maintainability
* statistical
@@ -80,11 +80,8 @@ class VariableDeclarationLine extends TVariableDeclarationInfo {
* (that is, the first is 0, the second is 1 and so on).
*/
private int getRank() {
line = rank[result](VariableDeclarationLine vdl, int l |
vdl = TVariableDeclarationLine(c, f, l)
|
l
)
line =
rank[result](VariableDeclarationLine vdl, int l | vdl = TVariableDeclarationLine(c, f, l) | l)
}
/**
@@ -133,7 +130,8 @@ class VariableDeclarationGroup extends VariableDeclarationLine {
* Gets the number of uniquely named `VariableDeclarationEntry`s in this group.
*/
int getCount() {
result = count(VariableDeclarationLine l |
result =
count(VariableDeclarationLine l |
l = getProximateNext*()
|
l.getAVDE().getVariable().getName()
@@ -166,7 +164,8 @@ class ExtClass extends Class {
from ExtClass c, int n, VariableDeclarationGroup vdg, string suffix
where
n = strictcount(string fieldName |
n =
strictcount(string fieldName |
exists(Field f |
f.getDeclaringType() = c and
fieldName = f.getName() and

View File

@@ -50,7 +50,8 @@ class BlockOrNonChild extends Element {
private int getNonContiguousStartRankIn(AffectedFile file) {
// When using `rank` with `order by`, the ranks may not be contiguous.
this = rank[result](BlockOrNonChild boc, int startLine, int startCol |
this =
rank[result](BlockOrNonChild boc, int startLine, int startCol |
boc.getLocation().hasLocationInfo(file.getAbsolutePath(), startLine, startCol, _, _)
|
boc order by startLine, startCol
@@ -58,13 +59,15 @@ class BlockOrNonChild extends Element {
}
int getStartRankIn(AffectedFile file) {
this.getNonContiguousStartRankIn(file) = rank[result](int rnk |
this.getNonContiguousStartRankIn(file) =
rank[result](int rnk |
exists(BlockOrNonChild boc | boc.getNonContiguousStartRankIn(file) = rnk)
)
}
int getNonContiguousEndRankIn(AffectedFile file) {
this = rank[result](BlockOrNonChild boc, int endLine, int endCol |
this =
rank[result](BlockOrNonChild boc, int endLine, int endCol |
boc.getLocation().hasLocationInfo(file.getAbsolutePath(), _, _, endLine, endCol)
|
boc order by endLine, endCol
@@ -79,9 +82,8 @@ predicate emptyBlockContainsNonchild(Block b) {
emptyBlock(_, b) and
exists(BlockOrNonChild c, AffectedFile file |
c.(BlockOrNonChild).getStartRankIn(file) = 1 + b.(BlockOrNonChild).getStartRankIn(file) and
c.(BlockOrNonChild).getNonContiguousEndRankIn(file) < b
.(BlockOrNonChild)
.getNonContiguousEndRankIn(file)
c.(BlockOrNonChild).getNonContiguousEndRankIn(file) <
b.(BlockOrNonChild).getNonContiguousEndRankIn(file)
)
}

View File

@@ -4,8 +4,9 @@
* @kind problem
* @problem.severity warning
* @id cpp/japanese-era/exact-era-date
* @precision medium
* @tags reliability
* @precision low
* @tags maintainability
* reliability
* japanese-era
*/

View File

@@ -307,7 +307,8 @@ predicate nonTrivialValue(string value, Literal literal) {
}
predicate valueOccurrenceCount(string value, int n) {
n = strictcount(Location loc |
n =
strictcount(Location loc |
exists(Literal lit | lit.getLocation() = loc | nonTrivialValue(value, lit)) and
// Exclude generated files (they do not have the same maintainability
// concerns as ordinary source files)
@@ -338,7 +339,8 @@ predicate check(Literal lit, string value, int n, File f) {
}
predicate checkWithFileCount(string value, int overallCount, int fileCount, File f) {
fileCount = strictcount(Location loc |
fileCount =
strictcount(Location loc |
exists(Literal lit | lit.getLocation() = loc | check(lit, value, overallCount, f))
)
}
@@ -364,7 +366,8 @@ predicate firstOccurrence(Literal lit, string value, int n) {
predicate magicConstant(Literal e, string msg) {
exists(string value, int n |
firstOccurrence(e, value, n) and
msg = "Magic constant: literal '" + value + "' is repeated " + n.toString() +
msg =
"Magic constant: literal '" + value + "' is repeated " + n.toString() +
" times and should be encapsulated in a constant."
)
}

View File

@@ -28,13 +28,15 @@ import cpp
// design question and carries has no safety risk.
predicate generatedCopyAssignment(CopyConstructor cc, string msg) {
cc.getDeclaringType().hasImplicitCopyAssignmentOperator() and
msg = "No matching copy assignment operator in class " + cc.getDeclaringType().getName() +
msg =
"No matching copy assignment operator in class " + cc.getDeclaringType().getName() +
". It is good practice to match a copy constructor with a " + "copy assignment operator."
}
predicate generatedCopyConstructor(CopyAssignmentOperator ca, string msg) {
ca.getDeclaringType().hasImplicitCopyConstructor() and
msg = "No matching copy constructor in class " + ca.getDeclaringType().getName() +
msg =
"No matching copy constructor in class " + ca.getDeclaringType().getName() +
". It is good practice to match a copy assignment operator with a " + "copy constructor."
}

View File

@@ -22,7 +22,7 @@ predicate testAndBranch(Expr e, Stmt branch) {
)
}
predicate choice(LocalScopeVariable v, Stmt branch, string value) {
predicate choice(StackVariable v, Stmt branch, string value) {
exists(AnalysedExpr e |
testAndBranch(e, branch) and
(
@@ -33,7 +33,7 @@ predicate choice(LocalScopeVariable v, Stmt branch, string value) {
)
}
predicate guarded(LocalScopeVariable v, Stmt loopstart, AnalysedExpr child) {
predicate guarded(StackVariable v, Stmt loopstart, AnalysedExpr child) {
choice(v, loopstart, _) and
loopstart.getChildStmt*() = child.getEnclosingStmt() and
(definition(v, child) or exists(child.getNullSuccessor(v)))
@@ -47,9 +47,7 @@ predicate addressLeak(Variable v, Stmt leak) {
)
}
from
LocalScopeVariable v, Stmt branch, AnalysedExpr cond, string context, string test,
string testresult
from StackVariable v, Stmt branch, AnalysedExpr cond, string context, string test, string testresult
where
choice(v, branch, context) and
forall(ControlFlowNode def | definition(v, def) and definitionReaches(def, cond) |

View File

@@ -23,14 +23,14 @@ predicate closeCall(FunctionCall fc, Variable v) {
)
}
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) {
predicate openDefinition(StackVariable 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())
exists(StackVariable v | openDefinition(v, def) and node = def.getASuccessor())
or
exists(LocalScopeVariable v, ControlFlowNode mid |
exists(StackVariable v, ControlFlowNode mid |
openDefinition(v, def) and
openReaches(def, mid) and
not errorSuccessor(v, mid) and
@@ -40,7 +40,7 @@ predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
)
}
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
predicate assignedToFieldOrGlobal(StackVariable v, Assignment assign) {
exists(Variable external |
assign.getRValue() = v.getAnAccess() and
assign.getLValue().(VariableAccess).getTarget() = external and
@@ -48,7 +48,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
)
}
from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret
from StackVariable v, ControlFlowNode def, ReturnStmt ret
where
openDefinition(v, def) and
openReaches(def, ret) and

View File

@@ -6,7 +6,7 @@
<overview>
<p>
This rule finds calls to <code>open</code> or <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
This rule finds calls to <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
Leaving descriptors open will cause a resource leak that will persist even after the program terminates.
</p>
@@ -14,7 +14,7 @@ Leaving descriptors open will cause a resource leak that will persist even after
</overview>
<recommendation>
<p>Ensure that all file or socket descriptors allocated by the program are freed before it terminates.</p>
<p>Ensure that all socket descriptors allocated by the program are freed before it terminates.</p>
</recommendation>
<example>

View File

@@ -1,6 +1,6 @@
/**
* @name Open descriptor never closed
* @description Functions that always return before closing the socket or file they opened leak resources.
* @description Functions that always return before closing the socket they opened leak resources.
* @kind problem
* @id cpp/descriptor-never-closed
* @problem.severity warning

View File

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

View File

@@ -11,7 +11,7 @@
import cpp
from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
where
checked = v.getAnAccess() and
dereferenced(checked) and

View File

@@ -13,7 +13,7 @@
import cpp
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
predicate negativeCheck(StackVariable v, ComparisonOperation op) {
exists(int varindex, string constant, Literal lit |
op.getChild(varindex) = v.getAnAccess() and
op.getChild(1 - varindex) = lit and
@@ -38,7 +38,7 @@ predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
)
}
from LocalScopeVariable v, ArrayExpr dangerous, Expr check
from StackVariable v, ArrayExpr dangerous, Expr check
where
useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and
negativeCheck(v, check) and

View File

@@ -1,14 +1,7 @@
import semmle.code.cpp.pointsto.PointsTo
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)
e = any(DeallocationExpr de).getFreedExpr()
or
exists(ExprCall c |
// cautiously assume that any ExprCall could be a freeCall.
@@ -22,7 +15,4 @@ class FreedExpr extends PointsToExpr {
override predicate interesting() { freed(this) }
}
predicate allocMayBeFreed(Expr alloc) {
isAllocationExpr(alloc) and
anythingPointsTo(alloc)
}
predicate allocMayBeFreed(AllocationExpr alloc) { anythingPointsTo(alloc) }

View File

@@ -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
@@ -24,7 +24,7 @@ predicate mayCallFunction(Expr call, Function f) {
predicate allocCallOrIndirect(Expr e) {
// direct alloc call
isAllocationExpr(e) and
e.(AllocationExpr).requiresDealloc() and
// We are only interested in alloc calls that are
// actually freed somehow, as MemoryNeverFreed
// will catch those that aren't.
@@ -53,8 +53,7 @@ predicate allocCallOrIndirect(Expr e) {
* can cause memory leaks.
*/
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified) {
reallocCall.getTarget().hasGlobalOrStdName("realloc") and
reallocCall.getArgument(0) = v.getAnAccess() and
reallocCall.(AllocationExpr).getReallocPtr() = v.getAnAccess() and
(
exists(Variable newV, ControlFlowNode node |
// a realloc followed by a null check at 'node' (return the non-null
@@ -71,23 +70,19 @@ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode
or
// a realloc(ptr, 0), which always succeeds and frees
// (return the realloc itself)
reallocCall.getArgument(1).getValue() = "0" and
reallocCall.(AllocationExpr).getReallocPtr().getValue() = "0" and
verified = reallocCall
)
}
predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
// direct free call
freeCall(n, v.getAnAccess()) and
not n.(FunctionCall).getTarget().hasGlobalOrStdName("realloc")
n.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
not exists(n.(AllocationExpr).getReallocPtr())
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
@@ -97,18 +92,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 +112,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 +129,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 +164,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 +185,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()
)

View File

@@ -11,6 +11,8 @@
import MemoryFreed
from Expr alloc
where isAllocationExpr(alloc) and not allocMayBeFreed(alloc)
from AllocationExpr alloc
where
alloc.requiresDealloc() and
not allocMayBeFreed(alloc)
select alloc, "This memory is never freed"

View File

@@ -43,7 +43,7 @@ class FunctionWithNegativeReturn extends Function {
predicate dangerousUse(IntegralReturnValue val, Expr use) {
exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val)
or
exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae |
exists(StackVariable v, ControlFlowNode def, ArrayExpr ae |
exprDefinition(v, def, val) and
use = ae.getArrayOffset() and
not boundsChecked(v, use) and
@@ -54,7 +54,7 @@ predicate dangerousUse(IntegralReturnValue val, Expr use) {
val = use and
use.getType().getUnderlyingType() instanceof PointerType
or
exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add |
exists(StackVariable v, ControlFlowNode def, AddExpr add |
exprDefinition(v, def, val) and
definitionUsePair(v, def, use) and
add.getAnOperand() = use and

View File

@@ -60,7 +60,7 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
pragma[nomagic]
private predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
exists(Expr mid |
not v instanceof LocalScopeVariable and
not v instanceof StackVariable and
v.getAnAssignedValue() = mid and
allocReaches0(mid, alloc, kind)
)
@@ -76,7 +76,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) {
allocExprOrIndirect(alloc, kind) and
e = alloc
or
exists(SsaDefinition def, LocalScopeVariable v |
exists(SsaDefinition def, StackVariable v |
// alloc via SSA
allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and
e = def.getAUse(v)

View File

@@ -11,26 +11,16 @@
*/
import cpp
class MallocCall extends FunctionCall {
MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") }
Expr getAllocatedSize() {
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)
}
}
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.models.interfaces.Allocation
predicate spaceProblem(FunctionCall append, string msg) {
exists(MallocCall malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer |
exists(
AllocationExpr malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer
|
add.getAChild() = strlen and
exists(add.getAChild().getValue()) and
malloc.getAllocatedSize() = add and
DataFlow::localExprFlow(add, malloc.getSizeExpr()) and
buffer.getAnAccess() = strlen.getStringExpr() and
(
insert.getTarget().hasGlobalOrStdName("strcpy") or
@@ -43,7 +33,8 @@ predicate spaceProblem(FunctionCall append, string msg) {
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 " +
msg =
"This buffer only contains enough room for '" + buffer.getName() + "' (copied on line " +
insert.getLocation().getStartLine().toString() + ")"
)
}

View File

@@ -51,7 +51,8 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
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() + "' <= " +
msg =
"Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
bufaccess.bufferSize().toString() + " elements."
)
@@ -106,8 +107,9 @@ 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 + "."
)
}
@@ -121,8 +123,9 @@ predicate outOfBounds(BufferAccess bufaccess, string msg) {
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."
msg =
"Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf + "[" +
access.toString() + "]' is accessed here."
)
}

View File

@@ -20,11 +20,10 @@ class ReturnPointsToExpr extends PointsToExpr {
ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this }
}
from ReturnPointsToExpr ret, LocalVariable local, float confidence
from ReturnPointsToExpr ret, StackVariable 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
select ret,

View File

@@ -23,7 +23,8 @@ predicate important(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 |
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

View File

@@ -20,11 +20,10 @@ class ScopeUtilityClass extends Class {
Call getAUse() { result = this.getAConstructor().getACallToThisFunction() }
}
from LocalScopeVariable v, ControlFlowNode def
from StackVariable v, ControlFlowNode def
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
not v.(Parameter).getInitializer().getExpr() = def and

View File

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

View File

@@ -18,14 +18,13 @@ string getCommentTextCaptioned(Comment c, string caption) {
dontCare = commentBody.regexpFind("\\n[/* \\t\\x0B\\f\\r]*" + caption, _, offset) and
interestingSuffix = commentBody.suffix(offset) and
endOfLine = interestingSuffix.indexOf("\n", 1, 0) and
captionedLine = interestingSuffix
captionedLine =
interestingSuffix
.prefix(endOfLine)
.regexpReplaceAll("^[/*\\s]*" + caption + "\\s*:?", "")
.trim() and
followingLine = interestingSuffix
.prefix(interestingSuffix.indexOf("\n", 2, 0))
.suffix(endOfLine)
.trim() and
followingLine =
interestingSuffix.prefix(interestingSuffix.indexOf("\n", 2, 0)).suffix(endOfLine).trim() and
if captionedLine = ""
then result = caption + " comment"
else

View File

@@ -56,7 +56,8 @@ VariableAccess getAnIncrement(Variable var) {
exists(AssignAddExpr a | a.getLValue() = result and a.getRValue().getValue().toInt() > 0)
or
exists(AssignExpr a | a.getLValue() = result |
a.getRValue() = any(AddExpr ae |
a.getRValue() =
any(AddExpr ae |
ae.getAnOperand() = var.getAnAccess() and
ae.getAnOperand().getValue().toInt() > 0
)
@@ -72,7 +73,8 @@ VariableAccess getADecrement(Variable var) {
exists(AssignSubExpr a | a.getLValue() = result and a.getRValue().getValue().toInt() > 0)
or
exists(AssignExpr a | a.getLValue() = result |
a.getRValue() = any(SubExpr ae |
a.getRValue() =
any(SubExpr ae |
ae.getLeftOperand() = var.getAnAccess() and
ae.getRightOperand().getValue().toInt() > 0
)
@@ -128,14 +130,16 @@ where
exists(VariableAccess bound |
upperBoundCheck(loop, bound) and
reachesNoInc(bound, bound) and
msg = "The loop counter " + bound.getTarget().getName() +
msg =
"The loop counter " + bound.getTarget().getName() +
" is not always incremented in the loop body."
)
or
exists(VariableAccess bound |
lowerBoundCheck(loop, bound) and
reachesNoDec(bound, bound) and
msg = "The loop counter " + bound.getTarget().getName() +
msg =
"The loop counter " + bound.getTarget().getName() +
" is not always decremented in the loop body."
)
)

View File

@@ -21,6 +21,7 @@ where
if call.getTarget() = call.getEnclosingFunction()
then msg = "This call directly invokes its containing function $@."
else
msg = "The function " + call.getEnclosingFunction() +
msg =
"The function " + call.getEnclosingFunction() +
" is indirectly recursive via this call to $@."
select call, msg, call.getTarget(), call.getTarget().getName()

View File

@@ -17,7 +17,8 @@ predicate lockOrder(LockOperation outer, LockOperation inner) {
}
int orderCount(Declaration outerLock, Declaration innerLock) {
result = strictcount(LockOperation outer, LockOperation inner |
result =
strictcount(LockOperation outer, LockOperation inner |
outer.getLocked() = outerLock and
inner.getLocked() = innerLock and
lockOrder(outer, inner)
@@ -27,6 +28,6 @@ int orderCount(Declaration outerLock, Declaration innerLock) {
from LockOperation outer, LockOperation inner
where
lockOrder(outer, inner) and
orderCount(outer.getLocked(), inner.getLocked()) <= orderCount(inner.getLocked(),
outer.getLocked())
orderCount(outer.getLocked(), inner.getLocked()) <=
orderCount(inner.getLocked(), outer.getLocked())
select inner, "Out-of-order locks: A " + inner.say() + " usually precedes a $@.", outer, outer.say()

View File

@@ -81,10 +81,8 @@ class LockingPrimitive extends FunctionCall, LockOperation {
override Function getLocked() { result = this.getTarget() }
override UnlockOperation getMatchingUnlock() {
result.(UnlockingPrimitive).getTarget().getName() = this
.getTarget()
.getName()
.replaceAll("Lock", "Unlock")
result.(UnlockingPrimitive).getTarget().getName() =
this.getTarget().getName().replaceAll("Lock", "Unlock")
}
override string say() { result = "call to " + getLocked().getName() }

View File

@@ -29,7 +29,8 @@ where
numStmt(f, line) = cnt and
cnt > 1 and
o.onLine(f, line) and
o.getLocation().getStartColumn() = min(OneLineStmt other, int toMin |
o.getLocation().getStartColumn() =
min(OneLineStmt other, int toMin |
other.onLine(f, line) and toMin = other.getLocation().getStartColumn()
|
toMin

View File

@@ -14,7 +14,8 @@ import cpp
string var(Variable v) {
exists(int level | level = v.getType().getPointerIndirectionLevel() |
level > 2 and
result = "The type of " + v.getName() + " uses " + level +
result =
"The type of " + v.getName() + " uses " + level +
" levels of pointer indirection -- maximum allowed is 2."
)
}
@@ -22,7 +23,8 @@ string var(Variable v) {
string fun(Function f) {
exists(int level | level = f.getType().getPointerIndirectionLevel() |
level > 2 and
result = "The return type of " + f.getName() + " uses " + level +
result =
"The return type of " + f.getName() + " uses " + level +
" levels of pointer indirection -- maximum allowed is 2."
)
}

View File

@@ -12,7 +12,8 @@
import cpp
int firstCodeLine(File f) {
result = min(Declaration d, Location l, int toMin |
result =
min(Declaration d, Location l, int toMin |
(
l = d.getLocation() and
l.getFile() = f and

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:
@@ -57,13 +59,122 @@ Expr getMulOperand(MulExpr me) { result = me.getAnOperand() }
* ```
*/
int getEffectiveMulOperands(MulExpr me) {
result = count(Expr op |
result =
count(Expr op |
op = getMulOperand*(me) and
not op instanceof MulExpr and
not likelySmall(op)
)
}
/**
* 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 +212,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

@@ -52,10 +52,7 @@ predicate introducesNewField(Class derived, Class base) {
from DataFlow::PathNode source, DataFlow::PathNode sink, CastToPointerArithFlow cfg
where
cfg.hasFlowPath(source, sink) and
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() = sink
.getNode()
.asExpr()
.getFullyConverted()
.getUnspecifiedType()
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() =
sink.getNode().asExpr().getFullyConverted().getUnspecifiedType()
select sink, source, sink,
"Pointer arithmetic here may be done with the wrong type because of the cast $@.", source, "here"

View File

@@ -37,7 +37,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
pathMightOverflow = false and
source.(FunctionCall).getTarget().(Snprintf).returnsFullFormatLength()
or
exists(RangeSsaDefinition def, LocalScopeVariable v |
exists(RangeSsaDefinition def, StackVariable v |
flowsToDef(source, def, v, pathMightOverflow) and
sink = def.getAUse(v)
)
@@ -63,9 +63,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
* `pathMightOverflow` is true if there is an arithmetic operation
* on the path that might overflow.
*/
predicate flowsToDef(
Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
) {
predicate flowsToDef(Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow) {
// Might the current definition overflow?
exists(boolean otherMightOverflow | flowsToDefImpl(source, def, v, otherMightOverflow) |
if defMightOverflow(def, v)
@@ -86,7 +84,7 @@ predicate flowsToDef(
* the path. But it is a good way to reduce the number of false positives.
*/
predicate flowsToDefImpl(
Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow
) {
// Assignment or initialization: `e = v;`
exists(Expr e |

View File

@@ -130,11 +130,8 @@ predicate trivialConversion(ExpectedType expected, Type actual) {
or
// allow a pointer to any integral type of the same size
// (this permits signedness changes)
expected.(PointerType).getBaseType().(IntegralType).getSize() = actual
.(PointerType)
.getBaseType()
.(IntegralType)
.getSize()
expected.(PointerType).getBaseType().(IntegralType).getSize() =
actual.(PointerType).getBaseType().(IntegralType).getSize()
or
expected = actual
)

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

@@ -8,6 +8,7 @@
* @id cpp/leap-year/adding-365-days-per-year
* @precision medium
* @tags leap-year
* correctness
*/
import cpp

View File

@@ -6,6 +6,7 @@
* @id cpp/leap-year/unchecked-after-arithmetic-year-modification
* @precision medium
* @tags leap-year
* correctness
*/
import cpp

View File

@@ -8,6 +8,7 @@
* @id cpp/leap-year/unchecked-return-value-for-time-conversion-function
* @precision medium
* @tags leap-year
* correctness
*/
import cpp

View File

@@ -5,7 +5,7 @@
* @kind problem
* @problem.severity warning
* @id cpp/leap-year/unsafe-array-for-days-of-the-year
* @precision medium
* @precision low
* @tags security
* leap-year
*/

View File

@@ -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()
}
}
@@ -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

@@ -15,7 +15,10 @@ import cpp
from ExprInVoidContext op
where
op instanceof EQExpr
or
op.(FunctionCall).getTarget().hasName("operator==")
not op.isUnevaluated() and
(
op instanceof EQExpr
or
op.(FunctionCall).getTarget().hasName("operator==")
)
select op, "This '==' operator has no effect. The assignment ('=') operator was probably intended."

View File

@@ -65,11 +65,8 @@ predicate functionDefinedInIfDefRecursive(Function f) {
* break encapsulation.
*/
predicate baseCall(FunctionCall call) {
call.getNameQualifier().getQualifyingElement() = call
.getEnclosingFunction()
.getDeclaringType()
.(Class)
.getABaseClass+()
call.getNameQualifier().getQualifyingElement() =
call.getEnclosingFunction().getDeclaringType().(Class).getABaseClass+()
}
from PureExprInVoidContext peivc, Locatable parent, Locatable info, string info_text, string tail
@@ -84,8 +81,10 @@ where
not peivc.getEnclosingFunction().isDefaulted() and
not exists(Macro m | peivc = m.getAnInvocation().getAnExpandedElement()) and
not peivc.isFromTemplateInstantiation(_) and
not peivc.isFromUninstantiatedTemplate(_) and
parent = peivc.getParent() and
not parent.isInMacroExpansion() and
not peivc.isUnevaluated() and
not parent instanceof PureExprInVoidContext and
not peivc.getEnclosingFunction().isCompilerGenerated() and
not peivc.getType() instanceof UnknownType and

View File

@@ -35,7 +35,8 @@ predicate booleanLiteral(Literal l) {
string boolLiteralInLogicalOp(Literal literal) {
booleanLiteral(literal) and
literal.getParent() instanceof BinaryLogicalOperation and
result = "Literal value " + literal.getValueText() +
result =
"Literal value " + literal.getValueText() +
" is used in a logical expression; simplify or use a constant."
}

View File

@@ -40,7 +40,8 @@ where
l = v.log2().floor() and
if v = 2.pow(l)
then
msg = "Operand to short-circuiting operator looks like a flag (" + v + " = 2 ^ " + l +
msg =
"Operand to short-circuiting operator looks like a flag (" + v + " = 2 ^ " + l +
"), may be typo for bitwise operator."
else
exists(string kind |
@@ -49,7 +50,8 @@ where
or
e instanceof OctalLiteral and kind = "an octal literal"
) and
msg = "Operand to short-circuiting operator is " + kind +
msg =
"Operand to short-circuiting operator is " + kind +
", and therefore likely a flag; a bitwise operator may be intended."
)
select e, msg

View File

@@ -63,7 +63,8 @@ predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr
func = ce.getCondition()
)
) and
msg = "Return value of " + func.getTarget().getName() +
msg =
"Return value of " + func.getTarget().getName() +
" used directly in a conditional expression."
)
}

View File

@@ -111,17 +111,20 @@ predicate illDefinedForStmt(ForStmt for, string message) {
illDefinedForStmtWrongDirection(for, v, initialCondition, terminalCondition, isIncr) and
if for.conditionAlwaysFalse()
then
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
message =
"Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
forLoopdirection(isIncr) + " from a value (" + initialCondition +
"), but the terminal condition is always false."
else
if for.conditionAlwaysTrue()
then
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
message =
"Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
forLoopdirection(isIncr) + " from a value (" + initialCondition +
"), but the terminal condition is always true."
else
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
message =
"Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
forLoopdirection(isIncr) + " from a value (" + initialCondition +
"), but the terminal condition is " + forLoopTerminalConditionRelationship(isIncr) +
" (" + terminalCondition + ")."

View File

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

View File

@@ -122,7 +122,7 @@ class MallocSizeExpr extends BufferAccess, FunctionCall {
override Expr getPointer() { none() }
override Expr getAccessedLength() { result = getArgument(1) }
override Expr getAccessedLength() { result = getArgument(0) }
}
class NetworkFunctionCall extends FunctionCall {

View File

@@ -30,9 +30,9 @@ class SprintfCall extends FunctionCall {
predicate isDangerous() { this.getMaxConvertedLength() > this.getBufferSize() }
string getDescription() {
result = "This conversion may yield a string of length " +
this.getMaxConvertedLength().toString() + ", which exceeds the allocated buffer size of " +
this.getBufferSize().toString()
result =
"This conversion may yield a string of length " + this.getMaxConvertedLength().toString() +
", which exceeds the allocated buffer size of " + this.getBufferSize().toString()
}
}

View File

@@ -42,10 +42,8 @@ predicate hasNontrivialConversion(Expr e) {
hasNontrivialConversion(e.getConversion())
}
from LocalScopeVariable var, VariableAccess va, ReturnStmt r
from StackVariable var, VariableAccess va, ReturnStmt r
where
not var.isStatic() and
not var.isThreadLocal() and
not var.getUnspecifiedType() instanceof ReferenceType and
not r.isFromUninstantiatedTemplate(_) and
va = var.getAnAccess() and

View File

@@ -12,7 +12,7 @@
*/
import cpp
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
import semmle.code.cpp.controlflow.StackVariableReachability
/**
* Auxiliary predicate: Types that don't require initialization
@@ -40,23 +40,17 @@ DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and
not exists(v.getInitializer()) and
/* The type of the variable is not stack-allocated. */
not allocatedType(v.getType()) and
/* The variable is not static (otherwise it is zeroed). */
not v.isStatic() and
/* The variable is not extern (otherwise it is zeroed). */
not v.hasSpecifier("extern")
not allocatedType(v.getType())
}
class UninitialisedLocalReachability extends LocalScopeVariableReachability {
class UninitialisedLocalReachability extends StackVariableReachability {
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
node = declWithNoInit(v)
}
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVarActual(v, node) }
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
// only report the _first_ possibly uninitialized use
useOfVarActual(v, node) or
definitionBarrier(v, node)

View File

@@ -3,9 +3,20 @@
"qhelp.dtd">
<qhelp>
<overview>
<p>Using TLS or SSLv23 protool from the boost::asio library, but not disabling deprecated protocols or disabling minimum-recommended protocols.</p>
<p>Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols may expose the software to known vulnerabilities or permit weak encryption algorithms to be used. Disabling the minimum-recommended protocols is also flagged.</p>
</overview>
<recommendation>
<p>When using the TLS or SSLv23 protocol, set the <code>no_tlsv1</code> and <code>no_tlsv1_1</code> options, but do not set <code>no_tlsv1_2</code>. When using the SSLv23 protocol, also set the <code>no_sslv3</code> option.</p>
</recommendation>
<example>
<p>In the following example, the <code>no_tlsv1_1</code> option has not been set. Use of TLS 1.1 is not recommended.</p>
<sample src="TlsSettingsMisconfigurationBad.cpp"/>
<p>In the corrected example, the <code>no_tlsv1</code> and <code>no_tlsv1_1</code> options have both been set, ensuring the use of TLS 1.2 or later.</p>
<sample src="TlsSettingsMisconfigurationGood.cpp"/>
</example>
<references>
<li>
<a href="https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio.html">Boost.Asio documentation</a>.

View File

@@ -1,6 +1,6 @@
/**
* @name Boost_asio TLS Settings Misconfiguration
* @description Using TLS or SSLv23 protool from the boost::asio library, but not disabling deprecated protocols or disabling minimum-recommended protocols
* @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols.
* @kind problem
* @problem.severity error
* @id cpp/boost/tls_settings_misconfiguration

View File

@@ -0,0 +1,8 @@
void useTLS_bad()
{
boost::asio::ssl::context ctx(boost::asio::ssl::context::tls);
ctx.set_options(boost::asio::ssl::context::no_tlsv1); // BAD: missing no_tlsv1_1
// ...
}

View File

@@ -0,0 +1,8 @@
void useTLS_good()
{
boost::asio::ssl::context ctx(boost::asio::ssl::context::tls);
ctx.set_options(boost::asio::ssl::context::no_tlsv1 | boost::asio::ssl::context::no_tlsv1_1); // GOOD
// ...
}

View File

@@ -4,13 +4,22 @@
<qhelp>
<overview>
<p>Using boost::asio library but specifying a deprecated hardcoded protocol.</p>
<p>Using a deprecated hardcoded protocol instead of negotiting would lock your application to a protocol that has known vulnerabilities or weaknesses.</p>
</overview>
<recommendation>
<p>Only use modern protocols such as TLS 1.2 or TLS 1.3.</p>
</recommendation>
<example>
<p>In the following example, the <code>sslv2</code> protocol is specified. This protocol is out of date and its use is not recommended.</p>
<sample src="UseOfDeprecatedHardcodedProtocolBad.cpp"/>
<p>In the corrected example, the <code>tlsv13</code> protocol is used instead.</p>
<sample src="UseOfDeprecatedHardcodedProtocolGood.cpp"/>
</example>
<references>
<li>
<a href="https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio.html">Boost.Asio documentation</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,7 @@
void useProtocol_bad()
{
boost::asio::ssl::context ctx_sslv2(boost::asio::ssl::context::sslv2); // BAD: outdated protocol
// ...
}

View File

@@ -0,0 +1,7 @@
void useProtocol_good()
{
boost::asio::ssl::context cxt_tlsv13(boost::asio::ssl::context::tlsv13);
// ...
}

View File

@@ -28,7 +28,8 @@ class NullInstruction extends ConstantValueInstruction {
}
predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
bool = any(CompareInstruction cmp |
bool =
any(CompareInstruction cmp |
exists(NullInstruction null |
cmp.getLeft() = null and cmp.getRight() = checked
or
@@ -40,7 +41,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
)
)
or
bool = any(ConvertInstruction convert |
bool =
any(ConvertInstruction convert |
checked = convert.getUnary() and
convert.getResultType() instanceof BoolType and
checked.getResultType() instanceof PointerType

View File

@@ -17,7 +17,9 @@ where
hasSuperfluousConstReturn(f) and
if f.hasSpecifier("const") or f.isStatic()
then
message = "The 'const' modifier has no effect on return types. The 'const' modifying the return type can be removed."
message =
"The 'const' modifier has no effect on return types. The 'const' modifying the return type can be removed."
else
message = "The 'const' modifier has no effect on return types. For a const function, the 'const' should go after the parameter list."
message =
"The 'const' modifier has no effect on return types. For a const function, the 'const' should go after the parameter list."
select f, message

View File

@@ -0,0 +1,8 @@
/* '#include <stdlib.h>' was forgotton */
int main(void) {
/* 'int malloc()' assumed */
unsigned char *p = malloc(100);
*p = 'a';
return 0;
}

View File

@@ -0,0 +1,29 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>A function is called without a prior function declaration or definition.
When this happens, the compiler generates an implicit declaration of the function,
specifying an integer return type and no parameters.
If the implicit declaration does not match the true signature of the function, the
function may behave unpredictably.</p>
<p>This may indicate a misspelled function name, or that the required header containing
the function declaration has not been included.</p>
</overview>
<recommendation>
<p>Provide an explicit declaration of the function before invoking it.</p>
</recommendation>
<example><sample src="ImplicitFunctionDeclaration.c" />
</example>
<references>
<li>SEI CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL31-C.+Declare+identifiers+before+using+them">DCL31-C. Declare identifiers before using them</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,48 @@
/**
* @name Implicit function declaration
* @description An implicitly declared function is assumed to take no
* arguments and return an integer. If this assumption does not hold, it
* may lead to unpredictable behavior.
* @kind problem
* @problem.severity warning
* @precision high
* @id cpp/implicit-function-declaration
* @tags correctness
* maintainability
*/
import cpp
import MistypedFunctionArguments
import TooFewArguments
import TooManyArguments
import semmle.code.cpp.commons.Exclusions
predicate locInfo(Locatable e, File file, int line, int col) {
e.getFile() = file and
e.getLocation().getStartLine() = line and
e.getLocation().getStartColumn() = col
}
predicate sameLocation(FunctionDeclarationEntry fde, FunctionCall fc) {
exists(File file, int line, int col |
locInfo(fde, file, line, col) and
locInfo(fc, file, line, col)
)
}
predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
from FunctionDeclarationEntry fdeIm, FunctionCall fc
where
isCompiledAsC(fdeIm.getFile()) and
not isFromMacroDefinition(fc) and
fdeIm.isImplicit() and
sameLocation(fdeIm, fc) and
not mistypedFunctionArguments(fc, _, _) and
not tooFewArguments(fc, _) and
not tooManyArguments(fc, _)
select fc, "Function call implicitly declares '" + fdeIm.getName() + "'."

View File

@@ -12,95 +12,10 @@
*/
import cpp
predicate arithTypesMatch(Type arg, Type parm) {
arg = parm
or
arg.getSize() = parm.getSize() and
(
arg instanceof IntegralOrEnumType and
parm instanceof IntegralOrEnumType
or
arg instanceof FloatingPointType and
parm instanceof FloatingPointType
)
}
pragma[inline]
predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// conversion to/from pointers to void is allowed
arg instanceof VoidType
or
parm instanceof VoidType
}
pragma[inline]
predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
nestedPointerArgTypeMayBeUsed(arg, parm)
or
// nested pointers
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
}
pragma[inline]
predicate argTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// pointers to compatible types
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
// C11 arrays
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
}
// This predicate holds whenever expression `arg` may be used to initialize
// function parameter `parm` without need for run-time conversion.
pragma[inline]
predicate argMayBeUsed(Expr arg, Parameter parm) {
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
}
// True if function was ()-declared, but not (void)-declared or K&R-defined
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(Function f) {
exists(File file | file.compiledAsC() |
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
)
}
import MistypedFunctionArguments
from FunctionCall fc, Function f, Parameter p
where
f = fc.getTarget() and
p = f.getAParameter() and
hasZeroParamDecl(f) and
isCompiledAsC(f) and
not f.isVarargs() and
not f instanceof BuiltInFunction and
p.getIndex() < fc.getNumberOfArguments() and
// Parameter p and its corresponding call argument must have mismatched types
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
where mistypedFunctionArguments(fc, f, p)
select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(),
fc.getArgument(p.getIndex()) as arg, arg.toString(),
arg.getExplicitlyConverted().getUnspecifiedType() as atype, atype.toString(), p, p.getTypedName()

View File

@@ -0,0 +1,96 @@
/**
* Provides the implementation of the MistypedFunctionArguments query. The
* query is implemented as a library, so that we can avoid producing
* duplicate results in other similar queries.
*/
import cpp
private predicate arithTypesMatch(Type arg, Type parm) {
arg = parm
or
arg.getSize() = parm.getSize() and
(
arg instanceof IntegralOrEnumType and
parm instanceof IntegralOrEnumType
or
arg instanceof FloatingPointType and
parm instanceof FloatingPointType
)
}
pragma[inline]
private predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// conversion to/from pointers to void is allowed
arg instanceof VoidType
or
parm instanceof VoidType
}
pragma[inline]
private predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
nestedPointerArgTypeMayBeUsed(arg, parm)
or
// nested pointers
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
}
pragma[inline]
private predicate argTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// pointers to compatible types
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
// C11 arrays
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
}
// This predicate holds whenever expression `arg` may be used to initialize
// function parameter `parm` without need for run-time conversion.
pragma[inline]
private predicate argMayBeUsed(Expr arg, Parameter parm) {
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
}
// True if function was ()-declared, but not (void)-declared or K&R-defined
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
predicate mistypedFunctionArguments(FunctionCall fc, Function f, Parameter p) {
f = fc.getTarget() and
p = f.getAParameter() and
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
not f.isVarargs() and
not f instanceof BuiltInFunction and
p.getIndex() < fc.getNumberOfArguments() and
// Parameter p and its corresponding call argument must have mismatched types
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
}

View File

@@ -15,31 +15,8 @@
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(Function f) {
exists(File file | file.compiledAsC() |
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
)
}
import TooFewArguments
from FunctionCall fc, Function f
where
f = fc.getTarget() and
not f.isVarargs() and
not f instanceof BuiltInFunction and
hasZeroParamDecl(f) and
isCompiledAsC(f) and
// There is an explicit declaration of the function whose parameter count is larger
// than the number of call arguments
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() > fc.getNumberOfArguments()
)
where tooFewArguments(fc, f)
select fc, "This call has fewer arguments than required by $@.", f, f.toString()

View File

@@ -0,0 +1,34 @@
/**
* Provides the implementation of the TooFewArguments query. The
* query is implemented as a library, so that we can avoid producing
* duplicate results in other similar queries.
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
predicate tooFewArguments(FunctionCall fc, Function f) {
f = fc.getTarget() and
not f.isVarargs() and
not f instanceof BuiltInFunction and
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
// There is an explicit declaration of the function whose parameter count is larger
// than the number of call arguments
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() > fc.getNumberOfArguments()
)
}

View File

@@ -12,35 +12,8 @@
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
// or implicitly declared (i.e., lacking a prototype)
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.isImplicit() and
not fde.hasVoidParamList() and
fde.getNumberOfParameters() = 0 and
not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(Function f) {
exists(File file | file.compiledAsC() |
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
)
}
import TooManyArguments
from FunctionCall fc, Function f
where
f = fc.getTarget() and
not f.isVarargs() and
hasZeroParamDecl(f) and
isCompiledAsC(f) and
exists(f.getBlock()) and
// There must not exist a declaration with the number of parameters
// at least as large as the number of call arguments
not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() >= fc.getNumberOfArguments()
)
where tooManyArguments(fc, f)
select fc, "This call has more arguments than required by $@.", f, f.toString()

View File

@@ -0,0 +1,38 @@
/**
* Provides the implementation of the TooManyArguments query. The
* query is implemented as a library, so that we can avoid producing
* duplicate results in other similar queries.
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
// or implicitly declared (i.e., lacking a prototype)
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.isImplicit() and
not fde.hasVoidParamList() and
fde.getNumberOfParameters() = 0 and
not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
predicate tooManyArguments(FunctionCall fc, Function f) {
f = fc.getTarget() and
not f.isVarargs() and
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
exists(f.getBlock()) and
// There must not exist a declaration with the number of parameters
// at least as large as the number of call arguments
not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() >= fc.getNumberOfArguments()
)
}

View File

@@ -14,6 +14,7 @@ import cpp
from Class c, int n
where
c.fromSource() and
n = c.getMetrics().getNumberOfMembers() +
n =
c.getMetrics().getNumberOfMembers() +
sum(Function f | c.getACanonicalMemberFunction() = f | f.getMetrics().getNumberOfLinesOfCode())
select c, n order by n desc

View File

@@ -15,16 +15,15 @@ import cpp
from Class c, int ccLoc, int loc
where
c.fromSource() and
ccLoc = sum(Function f |
ccLoc =
sum(Function f |
c.getACanonicalMemberFunction() = f and
f.getMetrics().getCyclomaticComplexity() > 18
|
f.getMetrics().getNumberOfLinesOfCode()
) and
loc = sum(Function f |
c.getACanonicalMemberFunction() = f
|
f.getMetrics().getNumberOfLinesOfCode()
) + c.getMetrics().getNumberOfMembers() and
loc =
sum(Function f | c.getACanonicalMemberFunction() = f | f.getMetrics().getNumberOfLinesOfCode()) +
c.getMetrics().getNumberOfMembers() and
loc != 0
select c, (ccLoc * 100).(float) / loc as n order by n desc

View File

@@ -76,7 +76,8 @@ class Library extends LibraryT {
* `sourceFile` is not in `destLib`).
*/
predicate libDependencies(File sourceFile, Library destLib, int num) {
num = strictcount(Element source, Element dest, File destFile |
num =
strictcount(Element source, Element dest, File destFile |
// dependency from source -> dest.
dependsOnSimple(source, dest) and
sourceFile = source.getFile() and
@@ -101,7 +102,7 @@ predicate libDependencies(File sourceFile, Library destLib, int num) {
predicate encodedDependencies(File source, string encodedDependency, int num) {
exists(Library destLib |
libDependencies(source, destLib, num) and
encodedDependency = "/" + source.getRelativePath() + "<|>" + destLib.getName() + "<|>" +
destLib.getVersion()
encodedDependency =
"/" + source.getRelativePath() + "<|>" + destLib.getName() + "<|>" + destLib.getVersion()
)
}

View File

@@ -85,7 +85,8 @@ private predicate closeWithDepth(int depth, File f, PreprocessorDirective close,
predicate length(PreprocessorDirective open, int length) {
exists(int depth, File f, int start, int end |
openWithDepth(depth, f, open, start) and
end = min(PreprocessorDirective endif, int closeLine |
end =
min(PreprocessorDirective endif, int closeLine |
closeWithDepth(depth, f, endif, closeLine) and
closeLine > start
|

View File

@@ -19,7 +19,8 @@ where
if loc > 0
then
// Weighted average of complexity by function length
complexity = sum(FunctionDeclarationEntry fde |
complexity =
sum(FunctionDeclarationEntry fde |
fde.getFile() = f
|
fde.getNumberOfLines() * fde.getCyclomaticComplexity()

View File

@@ -17,7 +17,8 @@ import external.CodeDuplication
from File f, int n
where
n = count(int line |
n =
count(int line |
exists(DuplicateBlock d | d.sourceFile() = f |
line in [d.sourceStartLine() .. d.sourceEndLine()]
) and

View File

@@ -15,7 +15,8 @@ import cpp
from File f, int n
where
f.fromSource() and
n = count(Comment c |
n =
count(Comment c |
c.getFile() = f and
(
c.getContents().matches("%TODO%") or

View File

@@ -20,7 +20,8 @@ predicate callToOperator(FunctionCall fc) {
from Function f, int n, int o
where
strictcount(f.getEntryPoint()) = 1 and
o = count(FunctionCall c |
o =
count(FunctionCall c |
c.getEnclosingFunction() = f and
not c.isInMacroExpansion() and
not c.isCompilerGenerated() and

View File

@@ -16,7 +16,8 @@ import external.VCS
from File f, int n
where
n = sum(Commit entry, int churn |
n =
sum(Commit entry, int churn |
churn = entry.getRecentChurnForFile(f) and
not artificialChange(entry)
|

View File

@@ -16,7 +16,8 @@ import external.VCS
from File f, int n
where
n = sum(Commit entry, int churn |
n =
sum(Commit entry, int churn |
churn = entry.getRecentAdditionsForFile(f) and
not artificialChange(entry)
|

View File

@@ -16,7 +16,8 @@ import external.VCS
from File f, int n
where
n = sum(Commit entry, int churn |
n =
sum(Commit entry, int churn |
churn = entry.getRecentDeletionsForFile(f) and
not artificialChange(entry)
|

View File

@@ -25,7 +25,8 @@ predicate inRange(Commit first, Commit second) {
}
int recommitsForFile(File f) {
result = count(Commit recommit |
result =
count(Commit recommit |
f = recommit.getAnAffectedFile() and
exists(Commit prev | inRange(prev, recommit))
)

View File

@@ -15,7 +15,8 @@ import external.VCS
from File f, int n
where
n = count(Commit e |
n =
count(Commit e |
e.getAnAffectedFile() = f and
e.daysToNow() <= 180 and
not artificialChange(e)

View File

@@ -147,7 +147,8 @@ library class SALElement extends Element {
exists(Location loc |
loc = this.(FunctionDeclarationEntry).getBlock().getLocation()
or
this = any(VariableDeclarationEntry vde |
this =
any(VariableDeclarationEntry vde |
vde.isDefinition() and
loc = vde.getVariable().getInitializer().getLocation()
)
@@ -194,7 +195,8 @@ private predicate salAnnotationPos(SALPosition pos) {
* ordering positions lexicographically by their start line and start column.
*/
private SALPosition salRelevantPositionAt(File file, int idx) {
result = rank[idx](SALPosition pos, int line, int col |
result =
rank[idx](SALPosition pos, int line, int col |
pos = MkSALPosition(file, line, col)
|
pos order by line, col

View File

@@ -21,6 +21,7 @@ where
if call.getTarget() = call.getEnclosingFunction()
then msg = "This call directly invokes its containing function $@."
else
msg = "The function " + call.getEnclosingFunction() +
msg =
"The function " + call.getEnclosingFunction() +
" is indirectly recursive via this call to $@."
select call, msg, call.getTarget(), call.getTarget().getName()

View File

@@ -58,7 +58,8 @@ VariableAccess getAnIncrement(Variable var) {
exists(AssignAddExpr a | a.getLValue() = result and a.getRValue().getValue().toInt() > 0)
or
exists(AssignExpr a | a.getLValue() = result |
a.getRValue() = any(AddExpr ae |
a.getRValue() =
any(AddExpr ae |
ae.getAnOperand() = var.getAnAccess() and
ae.getAnOperand().getValue().toInt() > 0
)
@@ -74,7 +75,8 @@ VariableAccess getADecrement(Variable var) {
exists(AssignSubExpr a | a.getLValue() = result and a.getRValue().getValue().toInt() > 0)
or
exists(AssignExpr a | a.getLValue() = result |
a.getRValue() = any(SubExpr ae |
a.getRValue() =
any(SubExpr ae |
ae.getLeftOperand() = var.getAnAccess() and
ae.getRightOperand().getValue().toInt() > 0
)
@@ -125,14 +127,16 @@ where
exists(VariableAccess bound |
upperBoundCheck(loop, bound) and
reachesNoInc(bound, bound) and
msg = "The loop counter " + bound.getTarget().getName() +
msg =
"The loop counter " + bound.getTarget().getName() +
" is not always incremented in the loop body."
)
or
exists(VariableAccess bound |
lowerBoundCheck(loop, bound) and
reachesNoDec(bound, bound) and
msg = "The loop counter " + bound.getTarget().getName() +
msg =
"The loop counter " + bound.getTarget().getName() +
" is not always decremented in the loop body."
)
)

View File

@@ -23,7 +23,8 @@ class MacroFunctionCall extends MacroInvocation {
}
int logicalLength(FunctionDeclarationEntry f) {
result = count(Stmt s |
result =
count(Stmt s |
s.getEnclosingFunction() = f.getFunction() and
s.getFile() = f.getFile() and
not s instanceof Block and

View File

@@ -39,7 +39,8 @@ where
numStmt(f, line) = cnt and
cnt > 1 and
o.onLine(f, line) and
o.getLocation().getStartColumn() = min(OneLineStmt other, int toMin |
o.getLocation().getStartColumn() =
min(OneLineStmt other, int toMin |
other.onLine(f, line) and toMin = other.getLocation().getStartColumn()
|
toMin

View File

@@ -23,7 +23,8 @@ class MacroFunctionCall extends MacroInvocation {
}
int logicalLength(FunctionDeclarationEntry f) {
result = count(Stmt s |
result =
count(Stmt s |
s.getEnclosingFunction() = f.getFunction() and
s.getFile() = f.getFile() and
not s instanceof Block and
@@ -34,7 +35,8 @@ int logicalLength(FunctionDeclarationEntry f) {
}
int assertionCount(FunctionDeclarationEntry f) {
result = count(Assertion a |
result =
count(Assertion a |
a.getAsserted().getEnclosingFunction() = f.getFunction() and a.getFile() = f.getFile()
)
}

View File

@@ -34,22 +34,24 @@ where
) and
if accessType = 1
then
message = "This '" + ba.getName() + "' operation accesses " +
plural(accessSize, " byte", " bytes") + " but the $@ is only " +
plural(bufferSize, " byte", " bytes") + "."
message =
"This '" + ba.getName() + "' operation accesses " + plural(accessSize, " byte", " bytes") +
" but the $@ is only " + plural(bufferSize, " byte", " bytes") + "."
else
if accessType = 2
then
message = "This '" + ba.getName() + "' operation may access " +
plural(accessSize, " byte", " bytes") + " but the $@ is only " +
plural(bufferSize, " byte", " bytes") + "."
message =
"This '" + ba.getName() + "' operation may access " + plural(accessSize, " byte", " bytes") +
" but the $@ is only " + plural(bufferSize, " byte", " bytes") + "."
else (
if accessSize > 0
then
message = "This array indexing operation accesses byte offset " + (accessSize - 1) +
message =
"This array indexing operation accesses byte offset " + (accessSize - 1) +
" but the $@ is only " + plural(bufferSize, " byte", " bytes") + "."
else
message = "This array indexing operation accesses a negative index " +
message =
"This array indexing operation accesses a negative index " +
((accessSize / ba.getActualType().getSize()) - 1) + " on the $@."
)
select ba, message, bufferAlloc, bufferDesc

View File

@@ -16,7 +16,7 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
import semmle.code.cpp.security.TaintTracking
predicate hasUpperBound(VariableAccess offsetExpr) {
exists(BasicBlock controlled, LocalScopeVariable offsetVar, SsaDefinition def |
exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def |
controlled.contains(offsetExpr) and
linearBoundControls(controlled, def, offsetVar) and
offsetExpr = def.getAUse(offsetVar)
@@ -24,7 +24,7 @@ predicate hasUpperBound(VariableAccess offsetExpr) {
}
pragma[noinline]
predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, LocalScopeVariable offsetVar) {
predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, StackVariable offsetVar) {
exists(GuardCondition guard, boolean branch |
guard.controls(controlled, branch) and
cmpWithLinearBound(guard, def.getAUse(offsetVar), Lesser(), branch)

View File

@@ -16,28 +16,32 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.models.implementations.Memcpy
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.Allocation
class MallocCall extends FunctionCall {
MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") }
Expr getAllocatedSize() {
if this.getArgument(0) instanceof VariableAccess
then
exists(LocalScopeVariable v, ControlFlowNode def |
definitionUsePair(v, def, this.getArgument(0)) and
exprDefinition(v, def, result)
predicate terminationProblem(AllocationExpr malloc, string msg) {
// malloc(strlen(...))
exists(StrlenCall strlen | DataFlow::localExprFlow(strlen, malloc.getSizeExpr())) and
// flows to a call that implies this is a null-terminated string
exists(ArrayFunction af, FunctionCall fc, int arg |
DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and
fc.getTarget() = af and
(
// flows into null terminated string argument
af.hasArrayWithNullTerminator(arg)
or
// flows into likely null terminated string argument (such as `strcpy`, `strcat`)
af.hasArrayWithUnknownSize(arg)
or
// flows into string argument to a formatting function (such as `printf`)
exists(int n, FormatLiteral fl |
fc.getArgument(arg) = fc.(FormattingFunctionCall).getConversionArgument(n) and
fl = fc.(FormattingFunctionCall).getFormat() and
fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
not fl.hasPrecision(n) // exclude: `%.*s`
)
else result = this.getArgument(0)
}
}
predicate terminationProblem(MallocCall malloc, string msg) {
malloc.getAllocatedSize() instanceof StrlenCall and
not exists(FunctionCall fc, MemcpyFunction memcpy, int ix |
DataFlow::localExprFlow(malloc, fc.getArgument(ix)) and
fc.getTarget() = memcpy and
memcpy.hasArrayOutput(ix)
)
) and
msg = "This allocation does not include space to null-terminate the string."
}

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

@@ -56,9 +56,12 @@ where
// very noisy on codebases that started as 32-bit
small.getExplicitlyConverted().getType().getSize() < 4 and
// Ignore cases where integer promotion has occurred on /, -, or >> expressions.
not getComparisonSize(large.(DivExpr).getLeftOperand().getExplicitlyConverted()) <= getComparisonSize(small) and
not getComparisonSize(large.(SubExpr).getLeftOperand().getExplicitlyConverted()) <= getComparisonSize(small) and
not getComparisonSize(large.(RShiftExpr).getLeftOperand().getExplicitlyConverted()) <= getComparisonSize(small) and
not getComparisonSize(large.(DivExpr).getLeftOperand().getExplicitlyConverted()) <=
getComparisonSize(small) and
not getComparisonSize(large.(SubExpr).getLeftOperand().getExplicitlyConverted()) <=
getComparisonSize(small) and
not getComparisonSize(large.(RShiftExpr).getLeftOperand().getExplicitlyConverted()) <=
getComparisonSize(small) and
// ignore loop-invariant smaller variables
loopVariant(small, l)
select rel,

View File

@@ -59,13 +59,15 @@ where
(
exists(BinaryLogicalOperation blop | blop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT") and
msg = "Usage of a type " + e1.getType().toString() +
msg =
"Usage of a type " + e1.getType().toString() +
" as an argument of a binary logical operation"
)
or
exists(UnaryLogicalOperation ulop | ulop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT") and
msg = "Usage of a type " + e1.getType().toString() +
msg =
"Usage of a type " + e1.getType().toString() +
" as an argument of a unary logical operation"
) and
not isHresultBooleanConverted(e1)

View File

@@ -82,7 +82,7 @@ FunctionCall stat(Expr path, Expr buf) {
predicate referenceTo(Expr source, Expr use) {
source = use
or
exists(SsaDefinition def, LocalScopeVariable v |
exists(SsaDefinition def, StackVariable v |
def.getAnUltimateDefiningValue(v) = source and def.getAUse(v) = use
)
}
@@ -109,9 +109,7 @@ where
)
) and
// checkUse and opUse refer to the same SSA variable
exists(SsaDefinition def, LocalScopeVariable v |
def.getAUse(v) = checkUse and def.getAUse(v) = opUse
) and
exists(SsaDefinition def, StackVariable v | def.getAUse(v) = checkUse and def.getAUse(v) = opUse) and
// opUse looks like an operation on a filename
fc = filenameOperation(opUse) and
// the return value of check is used (possibly with one step of

Some files were not shown because too many files have changed in this diff Show More