Merge from master

This commit is contained in:
Dave Bartolomeo
2020-01-26 16:38:48 -07:00
176 changed files with 2037 additions and 1406 deletions

View File

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

View File

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

View File

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

View File

@@ -12,95 +12,10 @@
*/
import cpp
predicate arithTypesMatch(Type arg, Type parm) {
arg = parm
or
arg.getSize() = parm.getSize() and
(
arg instanceof IntegralOrEnumType and
parm instanceof IntegralOrEnumType
or
arg instanceof FloatingPointType and
parm instanceof FloatingPointType
)
}
pragma[inline]
predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// conversion to/from pointers to void is allowed
arg instanceof VoidType
or
parm instanceof VoidType
}
pragma[inline]
predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
nestedPointerArgTypeMayBeUsed(arg, parm)
or
// nested pointers
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
}
pragma[inline]
predicate argTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// pointers to compatible types
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
// C11 arrays
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
}
// This predicate holds whenever expression `arg` may be used to initialize
// function parameter `parm` without need for run-time conversion.
pragma[inline]
predicate argMayBeUsed(Expr arg, Parameter parm) {
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
}
// True if function was ()-declared, but not (void)-declared or K&R-defined
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(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()

View File

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

View File

@@ -15,31 +15,8 @@
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(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()

View File

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

View File

@@ -12,35 +12,8 @@
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
// or implicitly declared (i.e., lacking a prototype)
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.isImplicit() and
not fde.hasVoidParamList() and
fde.getNumberOfParameters() = 0 and
not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(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()

View File

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

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

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

View File

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

View File

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

View File

@@ -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. */

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -191,8 +191,6 @@ class DataFlowExpr = Expr;
class DataFlowType = Type;
class DataFlowLocation = Location;
/** A function call relevant for data flow. */
class DataFlowCall extends CallInstruction {
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 *)... | |

View File

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

View 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 *));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
| Test for deprecated library StackVariableReachability. |

View File

@@ -1,4 +0,0 @@
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
select "Test for deprecated library StackVariableReachability."

View File

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

View File

@@ -1 +0,0 @@
Best Practices/Unused Entities/UnusedStaticFunctions.ql

View File

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

View File

@@ -1 +0,0 @@
Best Practices/Unused Entities/UnusedStaticFunctions.ql

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql

View File

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

View File

@@ -0,0 +1,6 @@
void implicit_declaration(int x) {}
int implicit_declaration_k_and_r(x) int x;
{
return x;
}

View File

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

View File

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

View File

@@ -1,2 +0,0 @@
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql