mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Merge from master
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
/* '#include <stdlib.h>' was forgotton */
|
||||
|
||||
int main(void) {
|
||||
/* 'int malloc()' assumed */
|
||||
unsigned char *p = malloc(100);
|
||||
*p = 'a';
|
||||
return 0;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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() + "'."
|
||||
@@ -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(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
import MistypedFunctionArguments
|
||||
|
||||
from FunctionCall fc, Function f, Parameter p
|
||||
where
|
||||
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)
|
||||
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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
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.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()
|
||||
)
|
||||
where tooFewArguments(fc, f)
|
||||
select fc, "This call has fewer arguments than required by $@.", f, f.toString()
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
@@ -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(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
import TooManyArguments
|
||||
|
||||
from FunctionCall fc, Function f
|
||||
where
|
||||
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()
|
||||
)
|
||||
where tooManyArguments(fc, f)
|
||||
select fc, "This call has more arguments than required by $@.", f, f.toString()
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -282,8 +282,6 @@ class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
|
||||
class DataFlowLocation = Location;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends Expr {
|
||||
DataFlowCall() { this instanceof Call }
|
||||
|
||||
@@ -68,9 +68,11 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
)
|
||||
or
|
||||
// Taint can flow through modeled functions
|
||||
exprToExprStep(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
or
|
||||
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
|
||||
or
|
||||
exprToExprStep(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
exprToPartialDefinitionStep(nodeFrom.asExpr(), nodeTo.asPartialDefinition())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,19 +135,30 @@ private predicate exprToExprStep(Expr exprIn, Expr exprOut) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintFunction f, Call call, FunctionOutput outModel |
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
exprOut = call and
|
||||
outModel.isReturnValueDeref() and
|
||||
exists(int argInIndex, FunctionInput inModel | f.hasTaintFlow(inModel, outModel) |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
(
|
||||
exprOut = call and
|
||||
outModel.isReturnValueDeref()
|
||||
or
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
call.passesByReference(argInIndex, exprIn)
|
||||
exprOut = call and
|
||||
outModel.isReturnValue()
|
||||
) and
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
(
|
||||
exists(int argInIndex |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
call.passesByReference(argInIndex, exprIn)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
inModel.isQualifierObject() and
|
||||
exprIn = call.getQualifier()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -163,11 +176,40 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintFunction f, Call call, FunctionOutput outModel, int argOutIndex |
|
||||
exists(
|
||||
TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel, int argOutIndex
|
||||
|
|
||||
call.getTarget() = f and
|
||||
argOut = call.getArgument(argOutIndex) and
|
||||
outModel.isParameterDeref(argOutIndex) and
|
||||
exists(int argInIndex, FunctionInput inModel | f.hasTaintFlow(inModel, outModel) |
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
(
|
||||
exists(int argInIndex |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
call.passesByReference(argInIndex, exprIn)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
or
|
||||
inModel.isQualifierObject() and
|
||||
exprIn = call.getQualifier()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprToPartialDefinitionStep(Expr exprIn, Expr exprOut) {
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
(
|
||||
exprOut = call.getQualifier() and
|
||||
outModel.isQualifierObject()
|
||||
) and
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
exists(int argInIndex |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
|
||||
@@ -19,33 +19,30 @@ private predicate predictableInstruction(Instruction instr) {
|
||||
predictableInstruction(instr.(UnaryInstruction).getUnary())
|
||||
}
|
||||
|
||||
private predicate userInputInstruction(Instruction instr) {
|
||||
exists(CallInstruction ci, WriteSideEffectInstruction wsei |
|
||||
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
|
||||
instr = wsei and
|
||||
wsei.getPrimaryInstruction() = ci
|
||||
)
|
||||
or
|
||||
userInputReturned(instr.getConvertedResultExpression())
|
||||
or
|
||||
isUserInput(instr.getConvertedResultExpression(), _)
|
||||
or
|
||||
instr.getConvertedResultExpression() instanceof EnvironmentRead
|
||||
or
|
||||
instr
|
||||
.(LoadInstruction)
|
||||
.getSourceAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable()
|
||||
.hasName("argv") and
|
||||
instr.getEnclosingFunction().hasGlobalName("main")
|
||||
}
|
||||
|
||||
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
|
||||
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
userInputInstruction(source.asInstruction())
|
||||
exists(CallInstruction ci, WriteSideEffectInstruction wsei |
|
||||
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
|
||||
source.asInstruction() = wsei and
|
||||
wsei.getPrimaryInstruction() = ci
|
||||
)
|
||||
or
|
||||
userInputReturned(source.asExpr())
|
||||
or
|
||||
isUserInput(source.asExpr(), _)
|
||||
or
|
||||
source.asExpr() instanceof EnvironmentRead
|
||||
or
|
||||
source
|
||||
.asInstruction()
|
||||
.(LoadInstruction)
|
||||
.getSourceAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable()
|
||||
.hasName("argv") and
|
||||
source.asInstruction().getEnclosingFunction().hasGlobalName("main")
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { any() }
|
||||
|
||||
@@ -83,10 +83,24 @@ private module VirtualDispatch {
|
||||
)
|
||||
or
|
||||
// Flow through global variable
|
||||
exists(StoreInstruction store, Variable var |
|
||||
exists(StoreInstruction store |
|
||||
store = src.asInstruction() and
|
||||
var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and
|
||||
this.flowsFromGlobal(var) and
|
||||
(
|
||||
exists(Variable var |
|
||||
var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and
|
||||
this.flowsFromGlobal(var)
|
||||
)
|
||||
or
|
||||
exists(Variable var, FieldAccess a |
|
||||
var = store
|
||||
.getDestinationAddress()
|
||||
.(FieldAddressInstruction)
|
||||
.getObjectAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable() and
|
||||
this.flowsFromGlobalUnionField(var, a)
|
||||
)
|
||||
) and
|
||||
allowFromArg = true
|
||||
)
|
||||
}
|
||||
@@ -97,6 +111,19 @@ private module VirtualDispatch {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var
|
||||
)
|
||||
}
|
||||
|
||||
private predicate flowsFromGlobalUnionField(Variable var, FieldAccess a) {
|
||||
a.getTarget().getDeclaringType() instanceof Union and
|
||||
exists(LoadInstruction load |
|
||||
this.flowsFrom(DataFlow::instructionNode(load), _) and
|
||||
load
|
||||
.getSourceAddress()
|
||||
.(FieldAddressInstruction)
|
||||
.getObjectAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable() = var
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Call through a function pointer. */
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -191,8 +191,6 @@ class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
|
||||
class DataFlowLocation = Location;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends CallInstruction {
|
||||
/**
|
||||
|
||||
@@ -55,6 +55,9 @@ class Node extends TIRDataFlowNode {
|
||||
*/
|
||||
Expr asConvertedExpr() { result = instr.getConvertedResultExpression() }
|
||||
|
||||
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = instr.(InitializeParameterInstruction).getParameter() }
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
| stackVariableReachability.c:11:2:11:2 | a | ... + ... |
|
||||
| stackVariableReachability.c:11:6:11:6 | a | 10 |
|
||||
| stackVariableReachability.c:12:2:12:2 | a | 40 |
|
||||
| stackVariableReachability.c:13:2:13:2 | a | 40 |
|
||||
| stackVariableReachability.c:14:4:14:4 | a | 40 |
|
||||
| stackVariableReachability.c:15:2:15:2 | a | call to f |
|
||||
| stackVariableReachability.c:15:8:15:8 | a | 40 |
|
||||
| stackVariableReachability.c:16:2:16:2 | a | call to f |
|
||||
| stackVariableReachability.c:19:3:19:3 | b | 50 |
|
||||
| stackVariableReachability.c:21:3:21:3 | b | 60 |
|
||||
| stackVariableReachability.c:23:2:23:2 | c | b |
|
||||
| stackVariableReachability.c:23:6:23:6 | b | 50, 60 |
|
||||
| stackVariableReachability.c:24:2:24:2 | c | 50, 60, b |
|
||||
@@ -0,0 +1,19 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
class MyStackVariableReachability extends StackVariableReachabilityWithReassignment {
|
||||
MyStackVariableReachability() { this = "MyStackVariableReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
exprDefinition(v, _, node)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
node.(VariableAccess).getTarget() = v
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
|
||||
}
|
||||
|
||||
from MyStackVariableReachability svr, ControlFlowNode sink
|
||||
select sink, strictconcat(Expr source | svr.reaches(source, _, sink) | source.toString(), ", ")
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
int cond();
|
||||
int f(int x);
|
||||
|
||||
void test(int p)
|
||||
{
|
||||
int a = 10;
|
||||
int b = 20;
|
||||
int c = 30;
|
||||
|
||||
a = a + 1;
|
||||
a = 40;
|
||||
a++;
|
||||
++a;
|
||||
a = f(a);
|
||||
a;
|
||||
|
||||
if (cond()) {
|
||||
b = 50;
|
||||
} else {
|
||||
b = 60;
|
||||
}
|
||||
c = b;
|
||||
c;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
| stackVariableReachability.c:11:2:11:2 | a | ... + ... |
|
||||
| stackVariableReachability.c:11:6:11:6 | a | 10 |
|
||||
| stackVariableReachability.c:12:2:12:2 | a | 40 |
|
||||
| stackVariableReachability.c:13:2:13:2 | a | 40 |
|
||||
| stackVariableReachability.c:14:4:14:4 | a | 40 |
|
||||
| stackVariableReachability.c:15:2:15:2 | a | call to f |
|
||||
| stackVariableReachability.c:15:8:15:8 | a | 40 |
|
||||
| stackVariableReachability.c:16:2:16:2 | a | call to f |
|
||||
| stackVariableReachability.c:19:3:19:3 | b | 50 |
|
||||
| stackVariableReachability.c:21:3:21:3 | b | 60 |
|
||||
| stackVariableReachability.c:23:2:23:2 | c | b |
|
||||
| stackVariableReachability.c:23:6:23:6 | b | 50, 60 |
|
||||
| stackVariableReachability.c:24:2:24:2 | c | b |
|
||||
@@ -0,0 +1,17 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
class MyStackVariableReachability extends StackVariableReachability {
|
||||
MyStackVariableReachability() { this = "MyStackVariableReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
node.(VariableAccess).getTarget() = v
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
|
||||
}
|
||||
|
||||
from MyStackVariableReachability svr, ControlFlowNode sink
|
||||
select sink, strictconcat(Expr source | svr.reaches(source, _, sink) | source.toString(), ", ")
|
||||
@@ -130,3 +130,46 @@ namespace virtual_inheritance {
|
||||
sink(topRef.isSource()); // flow [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
union union_with_sink_fun_ptrs {
|
||||
SinkFunctionType f;
|
||||
SinkFunctionType g;
|
||||
} u;
|
||||
|
||||
void call_sink_through_union_field_f(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void call_sink_through_union_field_g(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void set_global_union_field_f() {
|
||||
u.f = callSink;
|
||||
}
|
||||
|
||||
void test_call_sink_through_union() {
|
||||
set_global_union_field_f();
|
||||
call_sink_through_union_field_f(u.f);
|
||||
call_sink_through_union_field_g(u.g);
|
||||
}
|
||||
|
||||
union { union_with_sink_fun_ptrs u; } u2;
|
||||
|
||||
void call_sink_through_union_field_u_g(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void call_sink_through_union_field_u_f(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void set_global_union_field_u_f() {
|
||||
u2.u.f = callSink;
|
||||
}
|
||||
|
||||
void test_call_sink_through_union_2() {
|
||||
set_global_union_field_u_f();
|
||||
call_sink_through_union_field_u_f(u2.u.f); // flow [NOT DETECTED]
|
||||
call_sink_through_union_field_u_g(u2.u.g); // flow [NOT DETECTED]
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
| dispatch.cpp:73:14:73:19 | dispatch.cpp:23:38:23:38 | IR only |
|
||||
| dispatch.cpp:81:13:81:18 | dispatch.cpp:23:38:23:38 | IR only |
|
||||
| dispatch.cpp:107:17:107:22 | dispatch.cpp:96:8:96:8 | IR only |
|
||||
| dispatch.cpp:140:8:140:13 | dispatch.cpp:96:8:96:8 | IR only |
|
||||
| dispatch.cpp:144:8:144:13 | dispatch.cpp:96:8:96:8 | IR only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
| dispatch.cpp:55:22:55:30 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
|
||||
| dispatch.cpp:58:28:58:36 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
|
||||
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:107:17:107:22 | call to source |
|
||||
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:140:8:140:13 | call to source |
|
||||
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:144:8:144:13 | call to source |
|
||||
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
|
||||
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:14:23:19 | envStr | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:28 | call to getenv | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:40 | (const char *)... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:6:25:29 | ! ... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:12 | call to strcmp | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:29 | (bool)... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:14:25:19 | envStr | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:6:29:28 | ! ... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:12 | call to strcmp | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:28 | (bool)... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:14:29:19 | envStr | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:14:38:19 | envStr | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:28:50:40 | & ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:67:7:67:13 | copying | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | |
|
||||
@@ -0,0 +1,7 @@
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
|
||||
from Expr source, Element tainted, string globalVar
|
||||
where
|
||||
taintedIncludingGlobalVars(source, tainted, globalVar) and
|
||||
not tainted.getLocation().getFile().getExtension() = "h"
|
||||
select source, tainted, globalVar
|
||||
78
cpp/ql/test/library-tests/dataflow/security-taint/test.cpp
Normal file
78
cpp/ql/test/library-tests/dataflow/security-taint/test.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Test for the general-purpose taint-tracking
|
||||
// mechanism that is used by several of the security queries.
|
||||
|
||||
///// Library functions //////
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
int strcmp(const char *s1, const char *s2);
|
||||
char *getenv(const char *name);
|
||||
size_t strlen(const char *s);
|
||||
char *strcpy(char *s1, const char *s2);
|
||||
|
||||
void *malloc(size_t size);
|
||||
|
||||
int atoi(const char *nptr);
|
||||
|
||||
//// Test code /////
|
||||
|
||||
bool isAdmin = false;
|
||||
|
||||
void test1()
|
||||
{
|
||||
const char *envStr = getenv("USERINFO");
|
||||
|
||||
if (!strcmp(envStr, "admin")) {
|
||||
isAdmin = true;
|
||||
}
|
||||
|
||||
if (!strcmp(envStr, "none")) {
|
||||
isAdmin = false;
|
||||
}
|
||||
}
|
||||
|
||||
extern const char *specialUser;
|
||||
|
||||
void test2()
|
||||
{
|
||||
const char *envStr = getenv("USERINFO");
|
||||
|
||||
if (!strcmp(envStr, specialUser)) {
|
||||
isAdmin = true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *envStrGlobal;
|
||||
|
||||
void test3()
|
||||
{
|
||||
const char *envStr = getenv("USERINFO");
|
||||
const char **envStr_ptr = &envStrGlobal;
|
||||
|
||||
*envStr_ptr = envStr;
|
||||
|
||||
if (!strcmp(envStrGlobal, "admin")) {
|
||||
isAdmin = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bugWithBinop() {
|
||||
const char *userName = getenv("USER_NAME");
|
||||
|
||||
// The following is tainted, but should not cause
|
||||
// the whole program to be considered tainted.
|
||||
int bytes = strlen(userName) + 1;
|
||||
}
|
||||
|
||||
char* copying() {
|
||||
const char *userName = getenv("USER_NAME");
|
||||
char copy[1024];
|
||||
strcpy(copy, userName);
|
||||
return copy; // copy should be tainted
|
||||
}
|
||||
|
||||
void guard() {
|
||||
int len = atoi(getenv("FOOBAZ_BRANCHING"));
|
||||
if (len > 1000) return;
|
||||
char **node = (char **) malloc(len * sizeof(char *));
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
class TestAllocationConfig extends TaintTracking::Configuration {
|
||||
@@ -25,3 +26,39 @@ class TestAllocationConfig extends TaintTracking::Configuration {
|
||||
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
|
||||
}
|
||||
}
|
||||
|
||||
class SetMemberFunction extends TaintFunction {
|
||||
SetMemberFunction() { this.hasName("setMember") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
class GetMemberFunction extends TaintFunction {
|
||||
GetMemberFunction() { this.hasName("getMember") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
class SetStringFunction extends TaintFunction {
|
||||
SetStringFunction() { this.hasName("setString") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
class GetStringFunction extends TaintFunction {
|
||||
GetStringFunction() { this.hasName("getString") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,3 +347,62 @@
|
||||
| taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:390:2:390:28 | ... = ... | |
|
||||
| taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:392:7:392:7 | b | |
|
||||
| taint.cpp:390:13:390:27 | hello, world | taint.cpp:390:6:390:11 | call to wcsdup | TAINT |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:420:7:420:7 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:421:7:421:7 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:422:2:422:2 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:423:7:423:7 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:424:7:424:7 | a | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:426:7:426:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:427:7:427:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:428:2:428:2 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:429:7:429:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:430:7:430:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:431:7:431:7 | b | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:443:7:443:7 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:444:7:444:7 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:445:2:445:2 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:446:7:446:7 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:447:7:447:7 | d | |
|
||||
| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:422:2:422:2 | a | |
|
||||
| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:423:7:423:7 | a | |
|
||||
| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:424:7:424:7 | a | |
|
||||
| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:423:7:423:7 | a | |
|
||||
| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:424:7:424:7 | a | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:428:2:428:2 | b | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:429:7:429:7 | b | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:430:7:430:7 | b | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:431:7:431:7 | b | |
|
||||
| taint.cpp:428:2:428:2 | b [post update] | taint.cpp:429:7:429:7 | b | |
|
||||
| taint.cpp:428:2:428:2 | b [post update] | taint.cpp:430:7:430:7 | b | |
|
||||
| taint.cpp:428:2:428:2 | b [post update] | taint.cpp:431:7:431:7 | b | |
|
||||
| taint.cpp:428:2:428:20 | ... = ... | taint.cpp:430:9:430:14 | member | |
|
||||
| taint.cpp:428:13:428:18 | call to source | taint.cpp:428:2:428:20 | ... = ... | |
|
||||
| taint.cpp:433:6:433:20 | call to MyClass2 | taint.cpp:433:6:433:20 | new | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:433:2:433:20 | ... = ... | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:435:7:435:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:436:7:436:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:437:2:437:2 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:436:7:436:7 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:437:2:437:2 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:437:2:437:2 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:438:7:438:7 | ref arg c | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:438:7:438:7 | ref arg c | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:439:7:439:7 | c [post update] | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:441:9:441:9 | c | taint.cpp:441:2:441:9 | delete | TAINT |
|
||||
| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:445:2:445:2 | d | |
|
||||
| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:446:7:446:7 | d | |
|
||||
| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:447:7:447:7 | d | |
|
||||
| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:446:7:446:7 | d | |
|
||||
| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:447:7:447:7 | d | |
|
||||
|
||||
@@ -391,3 +391,58 @@ void test_wcsdup(wchar_t *source)
|
||||
sink(a); // tainted
|
||||
sink(b);
|
||||
}
|
||||
|
||||
// --- qualifiers ---
|
||||
|
||||
class MyClass2 {
|
||||
public:
|
||||
MyClass2(int value);
|
||||
void setMember(int value);
|
||||
int getMember();
|
||||
|
||||
int member;
|
||||
};
|
||||
|
||||
class MyClass3 {
|
||||
public:
|
||||
MyClass3(const char *string);
|
||||
void setString(const char *string);
|
||||
const char *getString();
|
||||
|
||||
const char *buffer;
|
||||
};
|
||||
|
||||
void test_qualifiers()
|
||||
{
|
||||
MyClass2 a(0), b(0), *c;
|
||||
MyClass3 d("");
|
||||
|
||||
sink(a);
|
||||
sink(a.getMember());
|
||||
a.setMember(source());
|
||||
sink(a); // tainted
|
||||
sink(a.getMember()); // tainted
|
||||
|
||||
sink(b);
|
||||
sink(b.getMember());
|
||||
b.member = source();
|
||||
sink(b); // tainted
|
||||
sink(b.member); // tainted
|
||||
sink(b.getMember());
|
||||
|
||||
c = new MyClass2(0);
|
||||
|
||||
sink(c);
|
||||
sink(c->getMember());
|
||||
c->setMember(source());
|
||||
sink(c); // tainted (deref)
|
||||
sink(c->getMember()); // tainted
|
||||
|
||||
delete c;
|
||||
|
||||
sink(d);
|
||||
sink(d.getString());
|
||||
d.setString(strings::source());
|
||||
sink(d); // tainted
|
||||
sink(d.getString()); // tainted
|
||||
}
|
||||
|
||||
@@ -39,3 +39,10 @@
|
||||
| taint.cpp:352:7:352:7 | b | taint.cpp:330:6:330:11 | call to source |
|
||||
| taint.cpp:372:7:372:7 | a | taint.cpp:365:24:365:29 | source |
|
||||
| taint.cpp:391:7:391:7 | a | taint.cpp:385:27:385:32 | source |
|
||||
| taint.cpp:423:7:423:7 | a | taint.cpp:422:14:422:19 | call to source |
|
||||
| taint.cpp:424:9:424:17 | call to getMember | taint.cpp:422:14:422:19 | call to source |
|
||||
| taint.cpp:430:9:430:14 | member | taint.cpp:428:13:428:18 | call to source |
|
||||
| taint.cpp:438:7:438:7 | c | taint.cpp:437:15:437:20 | call to source |
|
||||
| taint.cpp:439:10:439:18 | call to getMember | taint.cpp:437:15:437:20 | call to source |
|
||||
| taint.cpp:446:7:446:7 | d | taint.cpp:445:14:445:28 | call to source |
|
||||
| taint.cpp:447:9:447:17 | call to getString | taint.cpp:445:14:445:28 | call to source |
|
||||
|
||||
@@ -24,3 +24,11 @@
|
||||
| taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only |
|
||||
| taint.cpp:372:7:372:7 | taint.cpp:365:24:365:29 | AST only |
|
||||
| taint.cpp:391:7:391:7 | taint.cpp:385:27:385:32 | AST only |
|
||||
| taint.cpp:423:7:423:7 | taint.cpp:422:14:422:19 | AST only |
|
||||
| taint.cpp:424:9:424:17 | taint.cpp:422:14:422:19 | AST only |
|
||||
| taint.cpp:429:7:429:7 | taint.cpp:428:13:428:18 | IR only |
|
||||
| taint.cpp:430:9:430:14 | taint.cpp:428:13:428:18 | AST only |
|
||||
| taint.cpp:438:7:438:7 | taint.cpp:437:15:437:20 | AST only |
|
||||
| taint.cpp:439:10:439:18 | taint.cpp:437:15:437:20 | AST only |
|
||||
| taint.cpp:446:7:446:7 | taint.cpp:445:14:445:28 | AST only |
|
||||
| taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only |
|
||||
|
||||
@@ -17,3 +17,4 @@
|
||||
| taint.cpp:291:7:291:7 | y | taint.cpp:275:6:275:11 | call to source |
|
||||
| taint.cpp:337:7:337:7 | t | taint.cpp:330:6:330:11 | call to source |
|
||||
| taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source |
|
||||
| taint.cpp:429:7:429:7 | b | taint.cpp:428:13:428:18 | call to source |
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
| Test for deprecated library StackVariableReachability. |
|
||||
@@ -1,4 +0,0 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
select "Test for deprecated library StackVariableReachability."
|
||||
@@ -1,4 +0,0 @@
|
||||
| unused_functions.c:16:13:16:27 | unused_function | Static function unused_function is unreachable | unused_functions.c:16:13:16:27 | unused_function | unused_function |
|
||||
| unused_functions.c:20:13:20:28 | unused_function2 | Static function unused_function2 is unreachable ($@ must be removed at the same time) | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:24:13:24:28 | unused_function3 | Static function unused_function3 is unreachable | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:63:13:63:14 | h4 | Static function h4 is unreachable | unused_functions.c:63:13:63:14 | h4 | h4 |
|
||||
@@ -1 +0,0 @@
|
||||
Best Practices/Unused Entities/UnusedStaticFunctions.ql
|
||||
@@ -1,2 +0,0 @@
|
||||
| unused_mut.c:5:13:5:31 | mut_unused_function | Static function mut_unused_function is unreachable ($@ must be removed at the same time) | unused_mut.c:9:13:9:32 | mut_unused_function2 | mut_unused_function2 |
|
||||
| unused_mut.c:9:13:9:32 | mut_unused_function2 | Static function mut_unused_function2 is unreachable ($@ must be removed at the same time) | unused_mut.c:5:13:5:31 | mut_unused_function | mut_unused_function |
|
||||
@@ -1 +0,0 @@
|
||||
Best Practices/Unused Entities/UnusedStaticFunctions.ql
|
||||
@@ -1,3 +1,9 @@
|
||||
| unused_functions.c:16:13:16:27 | unused_function | Static function unused_function is unreachable | unused_functions.c:16:13:16:27 | unused_function | unused_function |
|
||||
| unused_functions.c:20:13:20:28 | unused_function2 | Static function unused_function2 is unreachable ($@ must be removed at the same time) | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:24:13:24:28 | unused_function3 | Static function unused_function3 is unreachable | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:63:13:63:14 | h4 | Static function h4 is unreachable | unused_functions.c:63:13:63:14 | h4 | h4 |
|
||||
| unused_mut.c:5:13:5:31 | mut_unused_function | Static function mut_unused_function is unreachable ($@ must be removed at the same time) | unused_mut.c:9:13:9:32 | mut_unused_function2 | mut_unused_function2 |
|
||||
| unused_mut.c:9:13:9:32 | mut_unused_function2 | Static function mut_unused_function2 is unreachable ($@ must be removed at the same time) | unused_mut.c:5:13:5:31 | mut_unused_function | mut_unused_function |
|
||||
| unused_static_functions.cpp:19:13:19:14 | f2 | Static function f2 is unreachable | unused_static_functions.cpp:19:13:19:14 | f2 | f2 |
|
||||
| unused_static_functions.cpp:33:13:33:14 | f5 | Static function f5 is unreachable ($@ must be removed at the same time) | unused_static_functions.cpp:34:13:34:14 | f6 | f6 |
|
||||
| unused_static_functions.cpp:34:13:34:14 | f6 | Static function f6 is unreachable ($@ must be removed at the same time) | unused_static_functions.cpp:33:13:33:14 | f5 | f5 |
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
| test2.c:28:19:28:20 | 41 | Potential buffer-overflow: 'buffer' has size 40 not 41. |
|
||||
| test2.c:29:26:29:27 | 43 | Potential buffer-overflow: 'buffer' has size 40 not 43. |
|
||||
| test2.c:31:26:31:27 | 44 | Potential buffer-overflow: 'buffer' has size 40 not 44. |
|
||||
| test2.c:32:25:32:26 | 45 | Potential buffer-overflow: 'buffer' has size 40 not 45. |
|
||||
| test2.c:33:26:33:27 | 46 | Potential buffer-overflow: 'buffer' has size 40 not 46. |
|
||||
| test2.c:34:22:34:23 | 47 | Potential buffer-overflow: 'buffer' has size 40 not 47. |
|
||||
| test2.c:35:23:35:24 | 48 | Potential buffer-overflow: 'buffer' has size 40 not 48. |
|
||||
| test.c:14:9:14:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[5]' is accessed here. |
|
||||
| test.c:15:9:15:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[6]' is accessed here. |
|
||||
| test.c:20:9:20:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[5]' is accessed here. |
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
| test.c:22:2:22:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.c:33:2:33:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:19:2:19:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:20:2:20:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:21:2:21:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
| test.c:28:3:28:12 | call to undeclared | Function call implicitly declares 'undeclared'. |
|
||||
| test.c:31:3:31:19 | call to not_yet_declared1 | Function call implicitly declares 'not_yet_declared1'. |
|
||||
| test.c:32:3:32:19 | call to not_yet_declared2 | Function call implicitly declares 'not_yet_declared2'. |
|
||||
| test.c:43:3:43:27 | call to not_declared_defined_with | Function call implicitly declares 'not_declared_defined_with'. |
|
||||
| test.c:54:3:54:21 | call to defined_with_double | Function call implicitly declares 'defined_with_double'. |
|
||||
| test.c:66:3:66:22 | call to defined_with_ptr_ptr | Function call implicitly declares 'defined_with_ptr_ptr'. |
|
||||
| test.c:68:3:68:22 | call to defined_with_ptr_arr | Function call implicitly declares 'defined_with_ptr_arr'. |
|
||||
| test.c:132:3:132:22 | call to implicit_declaration | Function call implicitly declares 'implicit_declaration'. |
|
||||
| test.c:133:3:133:30 | call to implicit_declaration_k_and_r | Function call implicitly declares 'implicit_declaration_k_and_r'. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
|
||||
@@ -25,11 +25,11 @@ void test(int *argv[]) {
|
||||
declared_void(); // GOOD
|
||||
declared_with(1); // GOOD
|
||||
|
||||
undeclared(); // GOOD
|
||||
undeclared(); // BAD (GOOD for everything except cpp/implicit-function-declaration)
|
||||
undeclared(1); // GOOD
|
||||
|
||||
not_yet_declared1(1); // GOOD
|
||||
not_yet_declared2(1); // GOOD
|
||||
not_yet_declared1(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
not_yet_declared2(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
not_yet_declared2(ca); // BAD
|
||||
not_yet_declared2(); // BAD
|
||||
|
||||
@@ -40,7 +40,7 @@ void test(int *argv[]) {
|
||||
declared_empty_defined_with(&x); // BAD
|
||||
declared_empty_defined_with(3, &x); // BAD
|
||||
|
||||
not_declared_defined_with(-1, 0, 2U); // GOOD
|
||||
not_declared_defined_with(-1, 0, 2U); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
not_declared_defined_with(4LL, 0, 2.5e9f); // BAD
|
||||
|
||||
declared_with_pointers(pv, ca); // GOOD
|
||||
@@ -51,7 +51,7 @@ void test(int *argv[]) {
|
||||
defined_with_float(2.f); // BAD
|
||||
defined_with_float(2.0); // BAD
|
||||
|
||||
defined_with_double(2.f); // GOOD
|
||||
defined_with_double(2.f); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
defined_with_double('c'); // BAD
|
||||
|
||||
defined_with_long_long('c'); // BAD
|
||||
@@ -63,9 +63,9 @@ void test(int *argv[]) {
|
||||
k_and_r_func(2.5, &s); // GOOD
|
||||
|
||||
int (*parameterName)[2];
|
||||
defined_with_ptr_ptr(parameterName); // GOOD
|
||||
defined_with_ptr_ptr(parameterName); // // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
defined_with_ptr_ptr(argv); // GOOD
|
||||
defined_with_ptr_arr(parameterName); // GOOD
|
||||
defined_with_ptr_arr(parameterName); // // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
defined_with_ptr_arr(argv); // GOOD
|
||||
|
||||
declared_and_defined_empty(); // GOOD
|
||||
@@ -124,3 +124,15 @@ int call_k_and_r(int i) {
|
||||
int will_be_k_and_r(val)
|
||||
int val;
|
||||
{ return val + 1; }
|
||||
|
||||
extern int extern_definition(double, double*);
|
||||
|
||||
void test_implicit_function_declaration(int x, double d) {
|
||||
int y;
|
||||
implicit_declaration(1, 2); // BAD
|
||||
implicit_declaration_k_and_r(1, 2); // BAD
|
||||
|
||||
implicit_declaration(1, 2); // GOOD (no longer an implicit declaration)
|
||||
|
||||
y = extern_definition(3.0f, &d); // GOOD
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
void implicit_declaration(int x) {}
|
||||
|
||||
int implicit_declaration_k_and_r(x) int x;
|
||||
{
|
||||
return x;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
| test.c:28:19:28:20 | 41 | Potential buffer-overflow: 'buffer' has size 40 not 41. |
|
||||
| test.c:29:26:29:27 | 43 | Potential buffer-overflow: 'buffer' has size 40 not 43. |
|
||||
| test.c:31:26:31:27 | 44 | Potential buffer-overflow: 'buffer' has size 40 not 44. |
|
||||
| test.c:32:25:32:26 | 45 | Potential buffer-overflow: 'buffer' has size 40 not 45. |
|
||||
| test.c:33:26:33:27 | 46 | Potential buffer-overflow: 'buffer' has size 40 not 46. |
|
||||
| test.c:34:22:34:23 | 47 | Potential buffer-overflow: 'buffer' has size 40 not 47. |
|
||||
| test.c:35:23:35:24 | 48 | Potential buffer-overflow: 'buffer' has size 40 not 48. |
|
||||
@@ -1 +0,0 @@
|
||||
Critical/OverflowStatic.ql
|
||||
@@ -1,2 +0,0 @@
|
||||
| test.c:22:2:22:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.c:33:2:33:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
@@ -1,2 +0,0 @@
|
||||
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
|
||||
|
||||
Reference in New Issue
Block a user