mirror of
https://github.com/github/codeql.git
synced 2025-12-20 18:56:32 +01:00
Merge remote-tracking branch 'upstream/master' into SimpleRangeAnalysis-use-after-cast
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
* readability
|
||||
*/
|
||||
import cpp
|
||||
private import semmle.code.cpp.commons.Exclusions
|
||||
private import semmle.code.cpp.rangeanalysis.PointlessComparison
|
||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import UnsignedGEZero
|
||||
@@ -31,6 +32,7 @@ from
|
||||
where
|
||||
not cmp.isInMacroExpansion() and
|
||||
not cmp.isFromTemplateInstantiation(_) and
|
||||
not functionContainsDisabledCode(cmp.getEnclosingFunction()) and
|
||||
reachablePointlessComparison(cmp, left, right, value, ss) and
|
||||
|
||||
// a comparison between an enum and zero is always valid because whether
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* external/cwe/cwe-561
|
||||
*/
|
||||
import cpp
|
||||
private import semmle.code.cpp.commons.Exclusions
|
||||
|
||||
class PureExprInVoidContext extends ExprInVoidContext {
|
||||
PureExprInVoidContext() { this.isPure() }
|
||||
@@ -23,71 +24,29 @@ predicate accessInInitOfForStmt(Expr e) {
|
||||
s.getExpr() = e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the preprocessor branch `pbd` is on line `pbdStartLine` in file `file`.
|
||||
*/
|
||||
predicate pbdLocation(PreprocessorBranchDirective pbd, string file, int pbdStartLine) {
|
||||
pbd.getLocation().hasLocationInfo(file, pbdStartLine, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the body of the function `f` is on lines `fBlockStartLine` to `fBlockEndLine` in file `file`.
|
||||
*/
|
||||
predicate functionLocation(Function f, string file, int fBlockStartLine, int fBlockEndLine) {
|
||||
f.getBlock().getLocation().hasLocationInfo(file, fBlockStartLine, _, fBlockEndLine, _)
|
||||
}
|
||||
/**
|
||||
* Holds if the function `f`, or a function called by it, contains
|
||||
* code excluded by the preprocessor.
|
||||
*/
|
||||
predicate containsDisabledCode(Function f) {
|
||||
// `f` contains a preprocessor branch that was not taken
|
||||
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int fBlockStartLine, int fBlockEndLine |
|
||||
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
|
||||
pbdLocation(pbd, file, pbdStartLine) and
|
||||
pbdStartLine <= fBlockEndLine and
|
||||
pbdStartLine >= fBlockStartLine and
|
||||
(
|
||||
pbd.(PreprocessorBranch).wasNotTaken() or
|
||||
|
||||
// an else either was not taken, or it's corresponding branch
|
||||
// was not taken.
|
||||
pbd instanceof PreprocessorElse
|
||||
)
|
||||
) or
|
||||
|
||||
predicate functionContainsDisabledCodeRecursive(Function f) {
|
||||
functionContainsDisabledCode(f) or
|
||||
// recurse into function calls
|
||||
exists(FunctionCall fc |
|
||||
fc.getEnclosingFunction() = f and
|
||||
containsDisabledCode(fc.getTarget())
|
||||
functionContainsDisabledCodeRecursive(fc.getTarget())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds if the function `f`, or a function called by it, is inside a
|
||||
* preprocessor branch that may have code in another arm
|
||||
*/
|
||||
predicate definedInIfDef(Function f) {
|
||||
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int pbdEndLine, int fBlockStartLine, int fBlockEndLine |
|
||||
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
|
||||
pbdLocation(pbd, file, pbdStartLine) and
|
||||
pbdLocation(pbd.getNext(), file, pbdEndLine) and
|
||||
pbdStartLine <= fBlockStartLine and
|
||||
pbdEndLine >= fBlockEndLine and
|
||||
// pbd is a preprocessor branch where multiple branches exist
|
||||
(
|
||||
pbd.getNext() instanceof PreprocessorElse or
|
||||
pbd instanceof PreprocessorElse or
|
||||
pbd.getNext() instanceof PreprocessorElif or
|
||||
pbd instanceof PreprocessorElif
|
||||
)
|
||||
) or
|
||||
|
||||
predicate functionDefinedInIfDefRecursive(Function f) {
|
||||
functionDefinedInIfDef(f) or
|
||||
// recurse into function calls
|
||||
exists(FunctionCall fc |
|
||||
fc.getEnclosingFunction() = f and
|
||||
definedInIfDef(fc.getTarget())
|
||||
functionDefinedInIfDefRecursive(fc.getTarget())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -121,8 +80,8 @@ where // EQExprs are covered by CompareWhereAssignMeant.ql
|
||||
not parent instanceof PureExprInVoidContext and
|
||||
not peivc.getEnclosingFunction().isCompilerGenerated() and
|
||||
not peivc.getType() instanceof UnknownType and
|
||||
not containsDisabledCode(peivc.(FunctionCall).getTarget()) and
|
||||
not definedInIfDef(peivc.(FunctionCall).getTarget()) and
|
||||
not functionContainsDisabledCodeRecursive(peivc.(FunctionCall).getTarget()) and
|
||||
not functionDefinedInIfDefRecursive(peivc.(FunctionCall).getTarget()) and
|
||||
if peivc instanceof FunctionCall then
|
||||
exists(Function target |
|
||||
target = peivc.(FunctionCall).getTarget() and
|
||||
|
||||
@@ -14,15 +14,20 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
|
||||
from Expr source, Expr tainted, BinaryArithmeticOperation oper,
|
||||
SizeofOperator sizeof, string taintCause
|
||||
where tainted(source, tainted)
|
||||
and oper.getAnOperand() = tainted
|
||||
and oper.getOperator() = "*"
|
||||
and oper.getAnOperand() = sizeof
|
||||
and oper != tainted
|
||||
and sizeof.getValue().toInt() > 1
|
||||
and isUserInput(source, taintCause)
|
||||
select
|
||||
oper, "This allocation size is derived from $@ and might overflow",
|
||||
source, "user input (" + taintCause + ")"
|
||||
predicate taintedAllocSize(Expr e, Expr source, string taintCause) {
|
||||
(
|
||||
isAllocationExpr(e) or
|
||||
any(MulExpr me | me.getAChild() instanceof SizeofOperator) = e
|
||||
) and
|
||||
exists(Expr tainted |
|
||||
tainted = e.getAChild() and
|
||||
tainted.getType().getUnspecifiedType() instanceof IntegralType and
|
||||
isUserInput(source, taintCause) and
|
||||
tainted(source, tainted)
|
||||
)
|
||||
}
|
||||
|
||||
from Expr e, Expr source, string taintCause
|
||||
where taintedAllocSize(e, source, taintCause)
|
||||
select e, "This allocation size is derived from $@ and might overflow", source,
|
||||
"user input (" + taintCause + ")"
|
||||
|
||||
@@ -68,6 +68,9 @@ some are after the final <code>#endif</code>. All three of these things must be
|
||||
<li>
|
||||
<a href="http://www.cplusplus.com/forum/articles/10627/">Headers and Includes: Why and How</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html">The Multiple-Include Optimization</a>
|
||||
</li>
|
||||
|
||||
|
||||
</references>
|
||||
|
||||
@@ -302,7 +302,13 @@ class File extends Container, @file {
|
||||
predicate compiledAsMicrosoft() {
|
||||
exists(Compilation c |
|
||||
c.getAFileCompiled() = this and
|
||||
c.getAnArgument() = "--microsoft"
|
||||
(
|
||||
c.getAnArgument() = "--microsoft" or
|
||||
c.getAnArgument().toLowerCase().replaceAll("\\", "/").matches("%/cl.exe")
|
||||
)
|
||||
) or exists(File parent |
|
||||
parent.compiledAsMicrosoft() and
|
||||
parent.getAnIncludedFile() = this
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,16 @@ predicate allocationFunction(Function f)
|
||||
name = "MmAllocateNodePagesForMdlEx" or
|
||||
name = "MmMapLockedPagesWithReservedMapping" or
|
||||
name = "MmMapLockedPages" or
|
||||
name = "MmMapLockedPagesSpecifyCache"
|
||||
name = "MmMapLockedPagesSpecifyCache" or
|
||||
name = "LocalAlloc" or
|
||||
name = "LocalReAlloc" or
|
||||
name = "GlobalAlloc" or
|
||||
name = "GlobalReAlloc" or
|
||||
name = "HeapAlloc" or
|
||||
name = "HeapReAlloc" or
|
||||
name = "VirtualAlloc" or
|
||||
name = "CoTaskMemAlloc" or
|
||||
name = "CoTaskMemRealloc"
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -81,7 +90,17 @@ predicate freeFunction(Function f, int argNum)
|
||||
(name = "MmFreeMappingAddress" and argNum = 0) or
|
||||
(name = "MmFreePagesFromMdl" and argNum = 0) or
|
||||
(name = "MmUnmapReservedMapping" and argNum = 0) or
|
||||
(name = "MmUnmapLockedPages" and argNum = 0)
|
||||
(name = "MmUnmapLockedPages" and argNum = 0) or
|
||||
(name = "LocalFree" and argNum = 0) or
|
||||
(name = "GlobalFree" and argNum = 0) or
|
||||
(name = "HeapFree" and argNum = 2) or
|
||||
(name = "VirtualFree" and argNum = 0) or
|
||||
(name = "CoTaskMemFree" and argNum = 0) or
|
||||
(name = "SysFreeString" and argNum = 0) or
|
||||
(name = "LocalReAlloc" and argNum = 0) or
|
||||
(name = "GlobalReAlloc" and argNum = 0) or
|
||||
(name = "HeapReAlloc" and argNum = 2) or
|
||||
(name = "CoTaskMemRealloc" and argNum = 0)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
60
cpp/ql/src/semmle/code/cpp/commons/Exclusions.qll
Normal file
60
cpp/ql/src/semmle/code/cpp/commons/Exclusions.qll
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Common predicates used to exclude results from a query based on heuristics.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Holds if the preprocessor branch `pbd` is on line `pbdStartLine` in file `file`.
|
||||
*/
|
||||
private predicate pbdLocation(PreprocessorBranchDirective pbd, string file, int pbdStartLine) {
|
||||
pbd.getLocation().hasLocationInfo(file, pbdStartLine, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the body of the function `f` is on lines `fBlockStartLine` to `fBlockEndLine` in file `file`.
|
||||
*/
|
||||
private predicate functionLocation(Function f, string file, int fBlockStartLine, int fBlockEndLine) {
|
||||
f.getBlock().getLocation().hasLocationInfo(file, fBlockStartLine, _, fBlockEndLine, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function `f` is inside a preprocessor branch that may have code in another arm.
|
||||
*/
|
||||
predicate functionDefinedInIfDef(Function f) {
|
||||
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int pbdEndLine, int fBlockStartLine,
|
||||
int fBlockEndLine |
|
||||
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
|
||||
pbdLocation(pbd, file, pbdStartLine) and
|
||||
pbdLocation(pbd.getNext(), file, pbdEndLine) and
|
||||
pbdStartLine <= fBlockStartLine and
|
||||
pbdEndLine >= fBlockEndLine and
|
||||
// pbd is a preprocessor branch where multiple branches exist
|
||||
(
|
||||
pbd.getNext() instanceof PreprocessorElse or
|
||||
pbd instanceof PreprocessorElse or
|
||||
pbd.getNext() instanceof PreprocessorElif or
|
||||
pbd instanceof PreprocessorElif
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function `f` contains code excluded by the preprocessor.
|
||||
*/
|
||||
predicate functionContainsDisabledCode(Function f) {
|
||||
// `f` contains a preprocessor branch that was not taken
|
||||
exists(PreprocessorBranchDirective pbd, string file, int pbdStartLine, int fBlockStartLine, int fBlockEndLine |
|
||||
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
|
||||
pbdLocation(pbd, file, pbdStartLine) and
|
||||
pbdStartLine <= fBlockEndLine and
|
||||
pbdStartLine >= fBlockStartLine and
|
||||
(
|
||||
pbd.(PreprocessorBranch).wasNotTaken() or
|
||||
|
||||
// an else either was not taken, or it's corresponding branch
|
||||
// was not taken.
|
||||
pbd instanceof PreprocessorElse
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -32,19 +32,19 @@ class AttributeFormattingFunction extends FormattingFunction {
|
||||
* A standard function such as `vprintf` that has a format parameter
|
||||
* and a variable argument list of type `va_arg`.
|
||||
*/
|
||||
predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex, boolean wide) {
|
||||
predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) {
|
||||
f.getName().regexpMatch("_?_?va?[fs]?n?w?printf(_s)?(_p)?(_l)?")
|
||||
and (
|
||||
if f.getName().matches("%\\_l")
|
||||
then formatParamIndex = f.getNumberOfParameters() - 3
|
||||
else formatParamIndex = f.getNumberOfParameters() - 2
|
||||
) and if f.getName().matches("%w%") then wide = true else wide = false
|
||||
)
|
||||
}
|
||||
|
||||
private
|
||||
predicate callsVariadicFormatter(Function f, int formatParamIndex, boolean wide) {
|
||||
predicate callsVariadicFormatter(Function f, int formatParamIndex) {
|
||||
exists(FunctionCall fc, int i |
|
||||
variadicFormatter(fc.getTarget(), i, wide)
|
||||
variadicFormatter(fc.getTarget(), i)
|
||||
and fc.getEnclosingFunction() = f
|
||||
and fc.getArgument(i) = f.getParameter(formatParamIndex).getAnAccess()
|
||||
)
|
||||
@@ -54,11 +54,11 @@ predicate callsVariadicFormatter(Function f, int formatParamIndex, boolean wide)
|
||||
* Holds if `f` is a function such as `vprintf` that has a format parameter
|
||||
* (at `formatParamIndex`) and a variable argument list of type `va_arg`.
|
||||
*/
|
||||
predicate variadicFormatter(Function f, int formatParamIndex, boolean wide) {
|
||||
primitiveVariadicFormatter(f, formatParamIndex, wide)
|
||||
predicate variadicFormatter(Function f, int formatParamIndex) {
|
||||
primitiveVariadicFormatter(f, formatParamIndex)
|
||||
or (
|
||||
not f.isVarargs()
|
||||
and callsVariadicFormatter(f, formatParamIndex, wide)
|
||||
and callsVariadicFormatter(f, formatParamIndex)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -68,12 +68,10 @@ predicate variadicFormatter(Function f, int formatParamIndex, boolean wide) {
|
||||
*/
|
||||
class UserDefinedFormattingFunction extends FormattingFunction {
|
||||
UserDefinedFormattingFunction() {
|
||||
isVarargs() and callsVariadicFormatter(this, _, _)
|
||||
isVarargs() and callsVariadicFormatter(this, _)
|
||||
}
|
||||
|
||||
override int getFormatParameterIndex() { callsVariadicFormatter(this, result, _) }
|
||||
|
||||
override predicate isWideCharDefault() { callsVariadicFormatter(this, _, true) }
|
||||
override int getFormatParameterIndex() { callsVariadicFormatter(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -674,8 +672,8 @@ class FormatLiteral extends Literal {
|
||||
/**
|
||||
* Gets the char type required by the nth conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char` for `printf`, `wchar_t` for `wprintf`).
|
||||
* - the `%S` format character reverses wideness.
|
||||
* (e.g. `char` for `printf`, `char` or `wchar_t` for `wprintf`).
|
||||
* - the `%C` format character reverses wideness.
|
||||
* - the size prefixes 'l'/'w' and 'h' override the type character
|
||||
* to wide or single-byte characters respectively.
|
||||
*/
|
||||
@@ -721,8 +719,8 @@ class FormatLiteral extends Literal {
|
||||
/**
|
||||
* Gets the string type required by the nth conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char` for `printf`, `wchar_t` for `wprintf`).
|
||||
* - the `%S` format character reverses wideness.
|
||||
* (e.g. `char *` for `printf`, `char *` or `wchar_t *` for `wprintf`).
|
||||
* - the `%S` format character reverses wideness on some platforms.
|
||||
* - the size prefixes 'l'/'w' and 'h' override the type character
|
||||
* to wide or single-byte characters respectively.
|
||||
*/
|
||||
|
||||
@@ -22,7 +22,7 @@ private Type stripTopLevelSpecifiersOnly(Type t) {
|
||||
*/
|
||||
Type getAFormatterWideType() {
|
||||
exists(FormattingFunction ff |
|
||||
result = stripTopLevelSpecifiersOnly(ff.getDefaultCharType()) and
|
||||
result = stripTopLevelSpecifiersOnly(ff.getFormatCharType()) and
|
||||
result.getSize() != 1
|
||||
)
|
||||
}
|
||||
@@ -46,6 +46,14 @@ abstract class FormattingFunction extends Function {
|
||||
/** Gets the position at which the format parameter occurs. */
|
||||
abstract int getFormatParameterIndex();
|
||||
|
||||
/**
|
||||
* Holds if this `FormattingFunction` is in a context that supports
|
||||
* Microsoft rules and extensions.
|
||||
*/
|
||||
predicate isMicrosoft() {
|
||||
getFile().compiledAsMicrosoft()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the default meaning of `%s` is a `wchar_t *`, rather than
|
||||
* a `char *` (either way, `%S` will have the opposite meaning).
|
||||
@@ -55,11 +63,10 @@ abstract class FormattingFunction extends Function {
|
||||
deprecated predicate isWideCharDefault() { none() }
|
||||
|
||||
/**
|
||||
* Gets the default character type expected for `%s` by this function. Typically
|
||||
* `char` or `wchar_t`.
|
||||
* Gets the character type used in the format string for this function.
|
||||
*/
|
||||
Type getDefaultCharType() {
|
||||
result =
|
||||
Type getFormatCharType() {
|
||||
result =
|
||||
stripTopLevelSpecifiersOnly(
|
||||
stripTopLevelSpecifiersOnly(
|
||||
getParameter(getFormatParameterIndex()).getType().getUnderlyingType()
|
||||
@@ -67,19 +74,33 @@ abstract class FormattingFunction extends Function {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default character type expected for `%s` by this function. Typically
|
||||
* `char` or `wchar_t`.
|
||||
*/
|
||||
Type getDefaultCharType() {
|
||||
(
|
||||
isMicrosoft() and
|
||||
result = getFormatCharType()
|
||||
) or (
|
||||
not isMicrosoft() and
|
||||
result instanceof PlainCharType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the non-default character type expected for `%S` by this function. Typically
|
||||
* `wchar_t` or `char`. On some snapshots there may be multiple results where we can't tell
|
||||
* which is correct for a particular function.
|
||||
*/
|
||||
Type getNonDefaultCharType() {
|
||||
(
|
||||
getDefaultCharType().getSize() = 1 and
|
||||
result = getAFormatterWideTypeOrDefault()
|
||||
) or (
|
||||
getDefaultCharType().getSize() > 1 and
|
||||
result instanceof PlainCharType
|
||||
)
|
||||
(
|
||||
getDefaultCharType().getSize() = 1 and
|
||||
result = getWideCharType()
|
||||
) or (
|
||||
not getDefaultCharType().getSize() = 1 and
|
||||
result instanceof PlainCharType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,10 +110,12 @@ abstract class FormattingFunction extends Function {
|
||||
*/
|
||||
Type getWideCharType() {
|
||||
(
|
||||
result = getDefaultCharType() or
|
||||
result = getNonDefaultCharType()
|
||||
) and
|
||||
result.getSize() > 1
|
||||
result = getFormatCharType() and
|
||||
result.getSize() > 1
|
||||
) or (
|
||||
not getFormatCharType().getSize() > 1 and
|
||||
result = getAFormatterWideTypeOrDefault() // may have more than one result
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
41
cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll
Normal file
41
cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll
Normal file
@@ -0,0 +1,41 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.rangeanalysis.RangeSSA
|
||||
|
||||
/**
|
||||
* Holds if `guard` won't return the value `polarity` when either
|
||||
* operand is NaN.
|
||||
*/
|
||||
predicate nanExcludingComparison(ComparisonOperation guard, boolean polarity) {
|
||||
polarity = true and
|
||||
(
|
||||
guard instanceof LTExpr or
|
||||
guard instanceof LEExpr or
|
||||
guard instanceof GTExpr or
|
||||
guard instanceof GEExpr or
|
||||
guard instanceof EQExpr
|
||||
)
|
||||
or
|
||||
polarity = false and
|
||||
guard instanceof NEExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a use of an SSA definition in `def` which cannot be NaN,
|
||||
* by virtue of the guard in `def`.
|
||||
*/
|
||||
private predicate excludesNan(RangeSsaDefinition def, VariableAccess v) {
|
||||
exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, LocalScopeVariable lsv |
|
||||
def.isGuardPhi(inCond, guard, branch) and
|
||||
inCond.getTarget() = lsv and
|
||||
v = def.getAUse(lsv) and
|
||||
guard.getAnOperand() = inCond and
|
||||
nanExcludingComparison(guard, branch)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable access which cannot be NaN.
|
||||
*/
|
||||
class NonNanVariableAccess extends VariableAccess {
|
||||
NonNanVariableAccess() { excludesNan(_, this) }
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import cpp
|
||||
private import RangeAnalysisUtils
|
||||
import RangeSSA
|
||||
import SimpleRangeAnalysisCached
|
||||
private import NanAnalysis
|
||||
|
||||
/**
|
||||
* This fixed set of lower bounds is used when the lower bounds of an
|
||||
@@ -993,6 +994,25 @@ predicate unanalyzableDefBounds(
|
||||
ub = varMaxVal(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if in the `branch` branch of a guard `guard` involving `v`,
|
||||
* we know that `v` is not NaN, and therefore it is safe to make range
|
||||
* inferences about `v`.
|
||||
*/
|
||||
bindingset[guard, v, branch]
|
||||
predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boolean branch) {
|
||||
v.getType().getUnspecifiedType() instanceof IntegralType
|
||||
or
|
||||
v.getType().getUnspecifiedType() instanceof FloatingPointType and v instanceof NonNanVariableAccess
|
||||
or
|
||||
// The reason the following case is here is to ensure that when we say
|
||||
// `if (x > 5) { ...then... } else { ...else... }`
|
||||
// it is ok to conclude that `x > 5` in the `then`, (though not safe
|
||||
// to conclude that x <= 5 in `else`) even if we had no prior
|
||||
// knowledge of `x` not being `NaN`.
|
||||
nanExcludingComparison(guard, branch)
|
||||
}
|
||||
|
||||
/**
|
||||
* If the guard is a comparison of the form `p*v + q <CMP> r`, then this
|
||||
* predicate uses the bounds information for `r` to compute a lower bound
|
||||
@@ -1004,10 +1024,12 @@ predicate lowerBoundFromGuard(
|
||||
) {
|
||||
exists (float childLB, RelationStrictness strictness
|
||||
| boundFromGuard(guard, v, childLB, true, strictness, branch)
|
||||
| if (strictness = Nonstrict() or
|
||||
not (v.getType().getUnspecifiedType() instanceof IntegralType))
|
||||
then lb = childLB
|
||||
else lb = childLB+1)
|
||||
| if nonNanGuardedVariable(guard, v, branch)
|
||||
then (if (strictness = Nonstrict() or
|
||||
not (v.getType().getUnspecifiedType() instanceof IntegralType))
|
||||
then lb = childLB
|
||||
else lb = childLB+1)
|
||||
else lb = varMinVal(v.getTarget()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1021,10 +1043,12 @@ predicate upperBoundFromGuard(
|
||||
) {
|
||||
exists (float childUB, RelationStrictness strictness
|
||||
| boundFromGuard(guard, v, childUB, false, strictness, branch)
|
||||
| if (strictness = Nonstrict() or
|
||||
not (v.getType().getUnspecifiedType() instanceof IntegralType))
|
||||
then ub = childUB
|
||||
else ub = childUB-1)
|
||||
| if nonNanGuardedVariable(guard, v, branch)
|
||||
then (if (strictness = Nonstrict() or
|
||||
not (v.getType().getUnspecifiedType() instanceof IntegralType))
|
||||
then ub = childUB
|
||||
else ub = childUB-1)
|
||||
else ub = varMaxVal(v.getTarget()))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import external.ExternalArtifact
|
||||
predicate printfLikeFunction(Function func, int formatArg) {
|
||||
(formatArg = func.(FormattingFunction).getFormatParameterIndex() and not func instanceof UserDefinedFormattingFunction)
|
||||
or
|
||||
primitiveVariadicFormatter(func, formatArg, _)
|
||||
primitiveVariadicFormatter(func, formatArg)
|
||||
or
|
||||
exists(ExternalData data |
|
||||
// TODO Do this \ to / conversion in the toolchain?
|
||||
|
||||
@@ -245,9 +245,14 @@ predicate insideFunctionValueMoveTo(Element src, Element dest)
|
||||
and format.getConversionChar(arg - formattingSend.getTarget().getNumberOfParameters()) = argFormat
|
||||
and (argFormat = "s" or argFormat = "S" or argFormat = "@"))
|
||||
// Expressions computed from tainted data are also tainted
|
||||
or (exists (FunctionCall call | dest = call and isPureFunction(call.getTarget().getName()) |
|
||||
call.getAnArgument() = src
|
||||
and forall(Expr arg | arg = call.getAnArgument() | arg = src or predictable(arg))))
|
||||
or exists(FunctionCall call | dest = call and isPureFunction(call.getTarget().getName()) |
|
||||
call.getAnArgument() = src and
|
||||
forall(Expr arg | arg = call.getAnArgument() | arg = src or predictable(arg)) and
|
||||
|
||||
// flow through `strlen` tends to cause dubious results, if the length is
|
||||
// bounded.
|
||||
not call.getTarget().getName() = "strlen"
|
||||
)
|
||||
or exists(Element a, Element b |
|
||||
moveToDependingOnSide(a, b) and
|
||||
if insideValueSource(a) then
|
||||
|
||||
@@ -315,3 +315,30 @@ int signedness_cast2(signed char c) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nan1(double x) {
|
||||
if (x < 0.0) {
|
||||
return 100;
|
||||
}
|
||||
else if (x >= 0.0) { // GOOD [x could be NaN]
|
||||
return 200;
|
||||
}
|
||||
else {
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
||||
int nan2(double x) {
|
||||
if (x == x) {
|
||||
// If x compares with anything at all, it's not NaN
|
||||
if (x < 0.0) {
|
||||
return 100;
|
||||
}
|
||||
else if (x >= 0.0) { // BAD [Always true]
|
||||
return 200;
|
||||
}
|
||||
else {
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,5 +36,6 @@
|
||||
| PointlessComparison.c:273:9:273:18 | ... > ... | Comparison is always false because c <= 0. |
|
||||
| PointlessComparison.c:283:13:283:19 | ... >= ... | Comparison is always true because c >= 11. |
|
||||
| PointlessComparison.c:294:9:294:16 | ... >= ... | Comparison is always false because ui1 <= 0. |
|
||||
| PointlessComparison.c:337:14:337:21 | ... >= ... | Comparison is always true because x >= 0. |
|
||||
| RegressionTests.cpp:57:7:57:22 | ... <= ... | Comparison is always true because * ... <= 4294967295. |
|
||||
| Templates.cpp:9:10:9:24 | ... <= ... | Comparison is always true because local <= 32767. |
|
||||
|
||||
@@ -66,3 +66,17 @@ int regression_test_01(unsigned long bb) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int containsIfDef(int x) {
|
||||
int result = 0;
|
||||
if (x > 0) {
|
||||
result = 1;
|
||||
}
|
||||
#if _CONDITION
|
||||
if (x < 0) {
|
||||
result = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result >= 0;
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
| tests.cpp:18:15:18:22 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:19:15:19:22 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:25:17:25:23 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *' |
|
||||
| tests.cpp:26:17:26:24 | Hello | This argument should be of type 'wchar_t *' but is of type 'char16_t *' |
|
||||
| tests.cpp:30:17:30:24 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:31:17:31:24 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:33:36:33:42 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
|
||||
| tests.cpp:35:36:35:43 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:38:36:38:43 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:39:36:39:43 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:26:17:26:24 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:27:17:27:24 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:29:17:29:23 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *' |
|
||||
| tests.cpp:30:17:30:24 | Hello | This argument should be of type 'wchar_t *' but is of type 'char16_t *' |
|
||||
| tests.cpp:34:36:34:43 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:35:36:35:43 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:37:36:37:42 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
|
||||
| tests.cpp:39:36:39:43 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:42:37:42:44 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:43:37:43:44 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:45:37:45:43 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
|
||||
| tests.cpp:47:37:47:44 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| tests.cpp:8:5:8:10 | printf | char | char16_t, wchar_t | char16_t, wchar_t |
|
||||
| tests.cpp:9:5:9:11 | wprintf | wchar_t | char | wchar_t |
|
||||
| tests.cpp:10:5:10:12 | swprintf | char16_t | char | char16_t |
|
||||
| tests.cpp:8:5:8:10 | printf | char | char | char16_t, wchar_t | char16_t, wchar_t |
|
||||
| tests.cpp:9:5:9:11 | wprintf | wchar_t | char | wchar_t | wchar_t |
|
||||
| tests.cpp:10:5:10:12 | swprintf | char16_t | char | char16_t | char16_t |
|
||||
|
||||
@@ -3,6 +3,7 @@ import cpp
|
||||
from FormattingFunction f
|
||||
select
|
||||
f,
|
||||
concat(f.getFormatCharType().toString(), ", "),
|
||||
concat(f.getDefaultCharType().toString(), ", "),
|
||||
concat(f.getNonDefaultCharType().toString(), ", "),
|
||||
concat(f.getWideCharType().toString(), ", ")
|
||||
|
||||
@@ -22,19 +22,27 @@ void tests() {
|
||||
printf("%S", u"Hello"); // GOOD
|
||||
printf("%S", L"Hello"); // GOOD
|
||||
|
||||
wprintf(L"%s", "Hello"); // BAD: expecting wchar_t
|
||||
wprintf(L"%s", u"Hello"); // BAD: expecting wchar_t
|
||||
wprintf(L"%s", L"Hello"); // GOOD
|
||||
wprintf(L"%s", "Hello"); // GOOD
|
||||
wprintf(L"%s", u"Hello"); // BAD: expecting char
|
||||
wprintf(L"%s", L"Hello"); // BAD: expecting char
|
||||
|
||||
wprintf(L"%S", "Hello"); // GOOD
|
||||
wprintf(L"%S", u"Hello"); // BAD: expecting char
|
||||
wprintf(L"%S", L"Hello"); // BAD: expecting char
|
||||
wprintf(L"%S", "Hello"); // BAD: expecting wchar_t
|
||||
wprintf(L"%S", u"Hello"); // BAD: expecting wchar_t
|
||||
wprintf(L"%S", L"Hello"); // GOOD
|
||||
|
||||
swprintf(buffer, BUF_SIZE, u"%s", "Hello"); // BAD: expecting char16_t
|
||||
swprintf(buffer, BUF_SIZE, u"%s", u"Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%s", L"Hello"); // BAD: expecting char16_t
|
||||
swprintf(buffer, BUF_SIZE, u"%s", "Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%s", u"Hello"); // BAD: expecting char
|
||||
swprintf(buffer, BUF_SIZE, u"%s", L"Hello"); // BAD: expecting char
|
||||
|
||||
swprintf(buffer, BUF_SIZE, u"%S", "Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%S", u"Hello"); // BAD: expecting char
|
||||
swprintf(buffer, BUF_SIZE, u"%S", L"Hello"); // BAD: expecting char
|
||||
swprintf(buffer, BUF_SIZE, u"%S", "Hello"); // BAD: expecting char16_t
|
||||
swprintf(buffer, BUF_SIZE, u"%S", u"Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%S", L"Hello"); // BAD: expecting char16_t
|
||||
|
||||
swprintf(buffer, BUF_SIZE, u"%hs", "Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%hs", u"Hello"); // BAD: expecting char
|
||||
swprintf(buffer, BUF_SIZE, u"%hs", L"Hello"); // BAD: expecting char
|
||||
|
||||
swprintf(buffer, BUF_SIZE, u"%ls", "Hello"); // BAD: expecting char16_t
|
||||
swprintf(buffer, BUF_SIZE, u"%ls", u"Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%ls", L"Hello"); // BAD: expecting char16_t
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
| printf.cpp:33:31:33:37 | test | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| printf.cpp:45:29:45:35 | test | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| printf.cpp:52:29:52:35 | test | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| printf.cpp:15:5:15:12 | swprintf | char16_t | char | char16_t |
|
||||
| printf.cpp:15:5:15:12 | swprintf | char | char16_t | char16_t |
|
||||
| printf.cpp:26:5:26:11 | sprintf | char | char16_t | char16_t |
|
||||
|
||||
@@ -30,7 +30,7 @@ int sprintf(char *dest, char *format, ...);
|
||||
void test1() {
|
||||
WCHAR string[20];
|
||||
|
||||
swprintf(string, u"test %s", u"test"); // GOOD
|
||||
swprintf(string, u"test %s", u"test"); // BAD: `char16_t` string parameter read as `char` string
|
||||
}
|
||||
|
||||
void test2() {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:126:18:126:19 | wc | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| printf1.h:127:18:127:18 | c | This argument should be of type 'wchar_t *' but is of type 'char *' |
|
||||
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |
|
||||
| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' |
|
||||
| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
| common.h:12:12:12:17 | printf | char | wchar_t | wchar_t |
|
||||
| common.h:15:12:15:18 | wprintf | wchar_t | char | wchar_t |
|
||||
| common.h:15:12:15:18 | wprintf | char | wchar_t | wchar_t |
|
||||
| format.h:4:13:4:17 | error | char | wchar_t | wchar_t |
|
||||
| real_world.h:8:12:8:18 | fprintf | char | wchar_t | wchar_t |
|
||||
| real_world.h:33:6:33:12 | msg_out | char | wchar_t | wchar_t |
|
||||
|
||||
@@ -119,3 +119,11 @@ void test_chars(char c, wchar_t wc, wint_t wt)
|
||||
wprintf(L"%C", wc); // GOOD (converts to wint_t)
|
||||
wprintf(L"%C", wt); // GOOD
|
||||
}
|
||||
|
||||
void test_ws(char *c, wchar_t *wc)
|
||||
{
|
||||
wprintf(L"%s", c); // GOOD
|
||||
wprintf(L"%s", wc); // BAD
|
||||
wprintf(L"%S", c); // BAD
|
||||
wprintf(L"%S", wc); // GOOD
|
||||
}
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
| printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:75:19:75:28 | sizeof(<expr>) | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:84:23:84:35 | ... - ... | This argument should be of type 'ssize_t' but is of type 'long long' |
|
||||
| printf1.h:125:18:125:18 | c | This argument should be of type '__wchar_t *' but is of type 'char *' |
|
||||
| printf1.h:128:18:128:19 | wc | This argument should be of type 'char *' but is of type '__wchar_t *' |
|
||||
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |
|
||||
| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' |
|
||||
| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' |
|
||||
| real_world.h:64:22:64:24 | & ... | This argument should be of type 'short *' but is of type 'signed int *' |
|
||||
| wide_string.h:25:18:25:20 | c | This argument should be of type 'char' but is of type 'char *' |
|
||||
| wide_string.h:29:19:29:22 | c | This argument should be of type 'wchar_t' but is of type '__wchar_t *' |
|
||||
|
||||
@@ -119,3 +119,11 @@ void test_chars(char c, wchar_t wc, wint_t wt)
|
||||
wprintf(L"%C", wc); // BAD [NOT DETECTED]
|
||||
wprintf(L"%C", wt); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_ws(char *c, wchar_t *wc, wint_t *wt)
|
||||
{
|
||||
wprintf(L"%s", c); // BAD
|
||||
wprintf(L"%s", wc); // GOOD
|
||||
wprintf(L"%S", c); // GOOD
|
||||
wprintf(L"%S", wc); // BAD
|
||||
}
|
||||
|
||||
@@ -26,5 +26,5 @@ void test_wchar4(char c, const char cc, wchar_t wc, const wchar_t wcc) {
|
||||
printf("%wc", wc); // GOOD
|
||||
printf("%wc", wcc); // GOOD
|
||||
printf("%wc", L'c'); // GOOD
|
||||
printf("%wc", L"c"); // BAD [NOT DETECTED]
|
||||
printf("%wc", L"c"); // BAD
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
| test.cpp:42:31:42:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:48:25:48:30 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:55:11:55:24 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-190/TaintedAllocationSize.ql
|
||||
@@ -0,0 +1,58 @@
|
||||
// Associated with CWE-190: Integer Overflow or Wraparound. http://cwe.mitre.org/data/definitions/190.html
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef struct {} FILE;
|
||||
|
||||
void *malloc(size_t size);
|
||||
void *realloc(void *ptr, size_t size);
|
||||
int atoi(const char *nptr);
|
||||
|
||||
struct MyStruct
|
||||
{
|
||||
char data[256];
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
basic_istream<charT,traits>& operator>>(int& n);
|
||||
};
|
||||
|
||||
typedef basic_istream<char> istream;
|
||||
|
||||
extern istream cin;
|
||||
}
|
||||
|
||||
int getTainted() {
|
||||
int i;
|
||||
|
||||
std::cin >> i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int tainted = atoi(argv[1]);
|
||||
|
||||
MyStruct *arr1 = (MyStruct *)malloc(sizeof(MyStruct)); // GOOD
|
||||
MyStruct *arr2 = (MyStruct *)malloc(tainted); // BAD
|
||||
MyStruct *arr3 = (MyStruct *)malloc(tainted * sizeof(MyStruct)); // BAD
|
||||
MyStruct *arr4 = (MyStruct *)malloc(getTainted() * sizeof(MyStruct)); // BAD [NOT DETECTED]
|
||||
MyStruct *arr5 = (MyStruct *)malloc(sizeof(MyStruct) + tainted); // BAD [NOT DETECTED]
|
||||
|
||||
int size = tainted * 8;
|
||||
char *chars1 = (char *)malloc(size); // BAD
|
||||
char *chars2 = new char[size]; // BAD
|
||||
char *chars3 = new char[8]; // GOOD
|
||||
|
||||
arr1 = (MyStruct *)realloc(arr1, sizeof(MyStruct) * tainted); // BAD
|
||||
|
||||
size = 8;
|
||||
chars3 = new char[size]; // GOOD [FALSE POSITIVE]
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -8,6 +8,3 @@
|
||||
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
|
||||
| test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
|
||||
| test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
|
||||
| test.c:74:7:74:10 | len5 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:71:19:71:22 | argv | User-provided value |
|
||||
| test.c:84:7:84:10 | len6 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:19:81:22 | argv | User-provided value |
|
||||
| test.c:94:7:94:10 | len7 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:91:19:91:22 | argv | User-provided value |
|
||||
|
||||
@@ -71,7 +71,7 @@ int main(int argc, char** argv) {
|
||||
len5 = strlen(argv[1]);
|
||||
while (len5)
|
||||
{
|
||||
len5--; // GOOD: can't underflow [FALSE POSITIVE]
|
||||
len5--; // GOOD: can't underflow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ int main(int argc, char** argv) {
|
||||
len6 = strlen(argv[1]);
|
||||
while (len6 != 0)
|
||||
{
|
||||
len6--; // GOOD: can't underflow [FALSE POSITIVE]
|
||||
len6--; // GOOD: can't underflow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ int main(int argc, char** argv) {
|
||||
len7 = strlen(argv[1]);
|
||||
while ((len7) && (1))
|
||||
{
|
||||
len7--; // GOOD: can't underflow [FALSE POSITIVE]
|
||||
len7--; // GOOD: can't underflow
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user