mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Merge remote-tracking branch 'upstream/master' into ir-crement-load
Update test output to fix semantic merge conflict.
This commit is contained in:
@@ -40,4 +40,4 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
|
||||
* The taint tracking library (`semmle.code.cpp.dataflow.TaintTracking`) has had
|
||||
the following improvements:
|
||||
* The library now models data flow through `strdup` and similar functions.
|
||||
|
||||
* The library now models data flow through formatting functions such as `sprintf`.
|
||||
|
||||
@@ -10,15 +10,25 @@ The following changes in version 1.24 affect Java analysis in all applications.
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
| Disabled Spring CSRF protection (`java/spring-disabled-csrf-protection`) | security, external/cwe/cwe-352 | Finds disabled Cross-Site Request Forgery (CSRF) protection in Spring. |
|
||||
| Failure to use HTTPS or SFTP URL in Maven artifact upload/download (`java/maven/non-https-url`) | security, external/cwe/cwe-300, external/cwe/cwe-319, external/cwe/cwe-494, external/cwe/cwe-829 | Finds use of insecure protocols during Maven dependency resolution. Results are shown on LGTM by default. |
|
||||
| Left shift by more than the type width (`java/lshift-larger-than-type-width`) | correctness | Finds left shifts of ints by 32 bits or more and left shifts of longs by 64 bits or more. Results are shown on LGTM by default. |
|
||||
| Suspicious date format (`java/suspicious-date-format`) | correctness | Finds date format patterns that use placeholders that are likely to be incorrect. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|------------------------------|------------------------|-----------------------------------|
|
||||
| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positives | Final fields with a non-null initializer are no longer reported. |
|
||||
| Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positives | Expressions of the form `0 * x` are usually intended and no longer reported. |
|
||||
| Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positives | Expressions of the form `0 * x` are usually intended and no longer reported. Also left shift of ints by 32 bits and longs by 64 bits are no longer reported as they are not constant, these results are instead reported by the new query `java/lshift-larger-than-type-width`. |
|
||||
| Useless null check (`java/useless-null-check`) | More true positives | Useless checks on final fields with a non-null initializer are now reported. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* Identification of test classes has been improved. Previously, one of the
|
||||
match conditions would classify any class with a name containing the string
|
||||
"Test" as a test class, but now this matching has been replaced with one that
|
||||
looks for the occurrence of actual unit-test annotations. This affects the
|
||||
general file classification mechanism and thus suppression of alerts, and
|
||||
also any security queries using taint tracking, as test classes act as
|
||||
default barriers stopping taint flow.
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
- [Electron](https://electronjs.org/)
|
||||
- [Node.js](https://nodejs.org/)
|
||||
- [Socket.IO](https://socket.io/)
|
||||
- [ws](https://github.com/websockets/ws)
|
||||
- [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
|
||||
|
||||
## New queries
|
||||
|
||||
@@ -36,6 +38,7 @@
|
||||
| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. |
|
||||
| Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. |
|
||||
| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. |
|
||||
| Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
|
||||
@@ -82,6 +82,14 @@
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll"
|
||||
],
|
||||
"IR IRConfiguration": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll"
|
||||
],
|
||||
"IR UseSoundEscapeAnalysis": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll"
|
||||
],
|
||||
"IR Operand Tag": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
This rule finds calls to <code>open</code> or <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
|
||||
This rule finds calls to <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
|
||||
Leaving descriptors open will cause a resource leak that will persist even after the program terminates.
|
||||
</p>
|
||||
|
||||
@@ -14,7 +14,7 @@ Leaving descriptors open will cause a resource leak that will persist even after
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Ensure that all file or socket descriptors allocated by the program are freed before it terminates.</p>
|
||||
<p>Ensure that all socket descriptors allocated by the program are freed before it terminates.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Open descriptor never closed
|
||||
* @description Functions that always return before closing the socket or file they opened leak resources.
|
||||
* @description Functions that always return before closing the socket they opened leak resources.
|
||||
* @kind problem
|
||||
* @id cpp/descriptor-never-closed
|
||||
* @problem.severity warning
|
||||
|
||||
@@ -163,5 +163,8 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
* An `int` that is a parameter index for some function. This is needed for binding in certain cases.
|
||||
*/
|
||||
class ParameterIndex extends int {
|
||||
ParameterIndex() { exists(Parameter p | this = p.getIndex()) }
|
||||
ParameterIndex() {
|
||||
exists(Parameter p | this = p.getIndex()) or
|
||||
exists(Call c | exists(c.getArgument(this))) // permit indexing varargs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,24 +132,38 @@ private predicate exprToExprStep(Expr exprIn, Expr exprOut) {
|
||||
// dest_ptr = strdup(tainted_ptr)
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintFunction f, Call call, 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)
|
||||
or
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
call.passesByReference(argInIndex, exprIn)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
(
|
||||
exprOut = call and
|
||||
outModel.isReturnValueDeref()
|
||||
or
|
||||
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.isQualifierObject() and
|
||||
exprIn = call.getQualifier()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
||||
@@ -160,14 +176,46 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
||||
// memcpy(&dest_var, tainted_ptr, len)
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
)
|
||||
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
|
||||
|
||||
@@ -4,6 +4,8 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
|
||||
private import semmle.code.cpp.models.interfaces.Taint
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
||||
/**
|
||||
* A predictable instruction is one where an external user can predict
|
||||
@@ -19,33 +21,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() }
|
||||
@@ -159,18 +158,79 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
|
||||
// This is part of the translation of `a[i]`, where we want taint to flow
|
||||
// from `a`.
|
||||
i2.(PointerAddInstruction).getLeft() = i1
|
||||
// TODO: robust Chi handling
|
||||
//
|
||||
// TODO: Flow from argument to return of known functions: Port missing parts
|
||||
// of `returnArgument` to the `interfaces.Taint` and `interfaces.DataFlow`
|
||||
// libraries.
|
||||
//
|
||||
// TODO: Flow from input argument to output argument of known functions: Port
|
||||
// missing parts of `copyValueBetweenArguments` to the `interfaces.Taint` and
|
||||
// `interfaces.DataFlow` libraries and implement call side-effect nodes. This
|
||||
// will help with the test for `ExecTainted.ql`. The test for
|
||||
// `TaintedPath.ql` is more tricky because the output arg is a pointer
|
||||
// addition expression.
|
||||
or
|
||||
// Flow from argument to return value
|
||||
i2 = any(CallInstruction call |
|
||||
exists(int indexIn |
|
||||
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
|
||||
i1 = getACallArgumentOrIndirection(call, indexIn)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Flow from input argument to output argument
|
||||
// TODO: This won't work in practice as long as all aliased memory is tracked
|
||||
// together in a single virtual variable.
|
||||
// TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
|
||||
// is a pointer addition expression?
|
||||
i2 = any(WriteSideEffectInstruction outNode |
|
||||
exists(CallInstruction call, int indexIn, int indexOut |
|
||||
modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and
|
||||
i1 = getACallArgumentOrIndirection(call, indexIn) and
|
||||
outNode.getIndex() = indexOut and
|
||||
outNode.getPrimaryInstruction() = call
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instruction that goes into argument `argumentIndex` of `call`. This
|
||||
* can be either directly or through one pointer indirection.
|
||||
*/
|
||||
private Instruction getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
|
||||
result = call.getPositionalArgument(argumentIndex)
|
||||
or
|
||||
exists(ReadSideEffectInstruction readSE |
|
||||
// TODO: why are read side effect operands imprecise?
|
||||
result = readSE.getSideEffectOperand().getAnyDef() and
|
||||
readSE.getPrimaryInstruction() = call and
|
||||
readSE.getIndex() = argumentIndex
|
||||
)
|
||||
}
|
||||
|
||||
private predicate modelTaintToParameter(Function f, int parameterIn, int parameterOut) {
|
||||
exists(FunctionInput modelIn, FunctionOutput modelOut |
|
||||
f.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
|
||||
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
|
||||
modelOut.isParameterDeref(parameterOut)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate modelTaintToReturnValue(Function f, int parameterIn) {
|
||||
// Taint flow from parameter to return value
|
||||
exists(FunctionInput modelIn, FunctionOutput modelOut |
|
||||
f.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
|
||||
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
|
||||
(modelOut.isReturnValue() or modelOut.isReturnValueDeref())
|
||||
)
|
||||
or
|
||||
// Data flow (not taint flow) to where the return value points. For the time
|
||||
// being we will conflate pointers and objects in taint tracking.
|
||||
exists(FunctionInput modelIn, FunctionOutput modelOut |
|
||||
f.(DataFlowFunction).hasDataFlow(modelIn, modelOut) and
|
||||
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
|
||||
modelOut.isReturnValueDeref()
|
||||
)
|
||||
or
|
||||
// Taint flow from one argument to another and data flow from an argument to a
|
||||
// return value. This happens in functions like `strcat` and `memcpy`. We
|
||||
// could model this flow in two separate steps, but that would add reverse
|
||||
// flow from the write side-effect to the call instruction, which may not be
|
||||
// desirable.
|
||||
exists(int parameterMid, InParameter modelMid, OutReturnValue returnOut |
|
||||
modelTaintToParameter(f, parameterIn, parameterMid) and
|
||||
modelMid.isParameter(parameterMid) and
|
||||
f.(DataFlowFunction).hasDataFlow(modelMid, returnOut)
|
||||
)
|
||||
}
|
||||
|
||||
private Element adjustedSink(DataFlow::Node sink) {
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -268,6 +268,7 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
|
||||
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or
|
||||
// Treat all conversions as flow, even conversions between different numeric types.
|
||||
iTo.(ConvertInstruction).getUnary() = iFrom or
|
||||
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom or
|
||||
iTo.(InheritanceConversionInstruction).getUnary() = iFrom or
|
||||
// A chi instruction represents a point where a new value (the _partial_
|
||||
// operand) may overwrite an old value (the _total_ operand), but the alias
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Module used to configure the IR generation process.
|
||||
*/
|
||||
|
||||
private import internal.IRConfigurationInternal
|
||||
|
||||
private newtype TIRConfiguration = MkIRConfiguration()
|
||||
@@ -13,3 +17,18 @@ class IRConfiguration extends TIRConfiguration {
|
||||
*/
|
||||
predicate shouldCreateIRForFunction(Language::Function func) { any() }
|
||||
}
|
||||
|
||||
private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control what escape analysis is used when generating SSA.
|
||||
*/
|
||||
class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration {
|
||||
string toString() { result = "IREscapeAnalysisConfiguration" }
|
||||
|
||||
/**
|
||||
* Holds if the escape analysis done by SSA construction should be sound. By default, the SSA is
|
||||
* built assuming that no variable's address ever escapes.
|
||||
*/
|
||||
predicate useSoundEscapeAnalysis() { none() }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import IRConfiguration
|
||||
|
||||
/**
|
||||
* Overrides the default IR configuration to use sound escape analysis, instead of assuming that
|
||||
* variable addresses never escape.
|
||||
*/
|
||||
class SoundEscapeAnalysisConfiguration extends IREscapeAnalysisConfiguration {
|
||||
override predicate useSoundEscapeAnalysis() { any() }
|
||||
}
|
||||
@@ -947,6 +947,10 @@ class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
|
||||
}
|
||||
|
||||
class CheckedConvertOrNullInstruction extends UnaryInstruction {
|
||||
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts between two addresses
|
||||
* related by inheritance.
|
||||
@@ -987,7 +991,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a direct non-virtual base class.
|
||||
* to the address of a base class.
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
|
||||
@@ -1198,52 +1202,63 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be read
|
||||
* by that call.
|
||||
* An instruction representing the side effect of a function call on any memory
|
||||
* that might be read by that call. This instruction is emitted instead of
|
||||
* `CallSideEffectInstruction` when it's certain that the call target cannot
|
||||
* write to escaped memory.
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a read side effect of a function call on a
|
||||
* specific parameter.
|
||||
*/
|
||||
class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode }
|
||||
|
||||
/** Gets the operand for the value that will be read from this instruction, if known. */
|
||||
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the value that will be read from this instruction, if known. */
|
||||
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }
|
||||
|
||||
/** Gets the operand for the address from which this instruction may read. */
|
||||
final AddressOperand getArgumentOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the address from which this instruction may read. */
|
||||
final Instruction getArgumentDef() { result = getArgumentOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class BufferReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
SizedBufferReadSideEffectInstruction() {
|
||||
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
|
||||
}
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
* An instruction representing a write side effect of a function call on a
|
||||
* specific parameter.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
@@ -2,6 +2,7 @@ private import AliasAnalysisInternal
|
||||
private import cpp
|
||||
private import InputIR
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private import semmle.code.cpp.ir.implementation.IRConfiguration
|
||||
private import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
@@ -95,6 +96,10 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
)
|
||||
or
|
||||
// Conversion using dynamic_cast results in an unknown offset
|
||||
instr instanceof CheckedConvertOrNullInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
@@ -277,9 +282,14 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||
* analysis.
|
||||
*/
|
||||
predicate variableAddressEscapes(IRVariable var) {
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable))
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable))
|
||||
)
|
||||
or
|
||||
// All variables with static storage duration have their address escape.
|
||||
// All variables with static storage duration have their address escape, even when escape analysis
|
||||
// is allowed to be unsound. Otherwise, we won't have a definition for any non-escaped global
|
||||
// variable. Normally, we rely on `AliasedDefinition` to handle that.
|
||||
not var instanceof IRAutomaticVariable
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class PropertyProvider extends IRPropertyProvider {
|
||||
exists(
|
||||
MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap
|
||||
|
|
||||
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and
|
||||
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex) and
|
||||
key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() +
|
||||
"]" and
|
||||
result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() +
|
||||
|
||||
@@ -947,6 +947,10 @@ class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
|
||||
}
|
||||
|
||||
class CheckedConvertOrNullInstruction extends UnaryInstruction {
|
||||
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts between two addresses
|
||||
* related by inheritance.
|
||||
@@ -987,7 +991,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a direct non-virtual base class.
|
||||
* to the address of a base class.
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
|
||||
@@ -1198,52 +1202,63 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be read
|
||||
* by that call.
|
||||
* An instruction representing the side effect of a function call on any memory
|
||||
* that might be read by that call. This instruction is emitted instead of
|
||||
* `CallSideEffectInstruction` when it's certain that the call target cannot
|
||||
* write to escaped memory.
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a read side effect of a function call on a
|
||||
* specific parameter.
|
||||
*/
|
||||
class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode }
|
||||
|
||||
/** Gets the operand for the value that will be read from this instruction, if known. */
|
||||
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the value that will be read from this instruction, if known. */
|
||||
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }
|
||||
|
||||
/** Gets the operand for the address from which this instruction may read. */
|
||||
final AddressOperand getArgumentOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the address from which this instruction may read. */
|
||||
final Instruction getArgumentDef() { result = getArgumentOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class BufferReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
SizedBufferReadSideEffectInstruction() {
|
||||
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
|
||||
}
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
* An instruction representing a write side effect of a function call on a
|
||||
* specific parameter.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
@@ -43,93 +43,34 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
|
||||
* Represents the IR translation of the declaration of a local variable,
|
||||
* including its initialization, if any.
|
||||
*/
|
||||
abstract class TranslatedVariableDeclaration extends TranslatedElement, InitializationContext {
|
||||
abstract class TranslatedLocalVariableDeclaration extends TranslatedVariableInitialization {
|
||||
/**
|
||||
* Gets the local variable being declared.
|
||||
*/
|
||||
abstract LocalVariable getVariable();
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
final override Type getTargetType() { result = getVariableType(getVariable()) }
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getTypeForGLValue(getVariableType(getVariable()))
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getTypeForPRValue(getVariableType(getVariable()))
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
kind instanceof GotoEdge and
|
||||
if hasUninitializedInstruction()
|
||||
then result = getInstruction(InitializerStoreTag())
|
||||
else result = getInitialization().getFirstInstruction()
|
||||
)
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
kind instanceof GotoEdge and
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
result = getInitialization().getFirstInstruction()
|
||||
or
|
||||
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag()
|
||||
or
|
||||
hasUninitializedInstruction() and tag = InitializerStoreTag()
|
||||
) and
|
||||
result = getIRUserVariable(getFunction(), getVariable())
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = getVariableType(getVariable()) }
|
||||
|
||||
private TranslatedInitialization getInitialization() {
|
||||
final override TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(getVariable()
|
||||
.getInitializer()
|
||||
.getExpr()
|
||||
.getFullyConverted())
|
||||
}
|
||||
|
||||
private predicate hasUninitializedInstruction() {
|
||||
not exists(getInitialization()) or
|
||||
getInitialization() instanceof TranslatedListInitialization or
|
||||
getInitialization() instanceof TranslatedConstructorInitialization or
|
||||
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
|
||||
final override Instruction getInitializationSuccessor() {
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
final override IRVariable getIRVariable() {
|
||||
result = getIRUserVariable(getFunction(), getVariable())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a local variable declaration within a declaration statement.
|
||||
*/
|
||||
class TranslatedVariableDeclarationEntry extends TranslatedVariableDeclaration,
|
||||
class TranslatedVariableDeclarationEntry extends TranslatedLocalVariableDeclaration,
|
||||
TranslatedDeclarationEntry {
|
||||
LocalVariable var;
|
||||
|
||||
@@ -151,7 +92,7 @@ TranslatedRangeBasedForVariableDeclaration getTranslatedRangeBasedForVariableDec
|
||||
/**
|
||||
* Represents the IR translation of a compiler-generated variable in a range-based `for` loop.
|
||||
*/
|
||||
class TranslatedRangeBasedForVariableDeclaration extends TranslatedVariableDeclaration,
|
||||
class TranslatedRangeBasedForVariableDeclaration extends TranslatedLocalVariableDeclaration,
|
||||
TTranslatedRangeBasedForVariableDeclaration {
|
||||
RangeBasedForStmt forStmt;
|
||||
LocalVariable var;
|
||||
@@ -181,7 +122,7 @@ TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class TranslatedConditionDecl extends TranslatedVariableDeclaration, TTranslatedConditionDecl {
|
||||
class TranslatedConditionDecl extends TranslatedLocalVariableDeclaration, TTranslatedConditionDecl {
|
||||
ConditionDeclExpr conditionDeclExpr;
|
||||
|
||||
TranslatedConditionDecl() { this = TTranslatedConditionDecl(conditionDeclExpr) }
|
||||
|
||||
@@ -1944,40 +1944,22 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||
* IR translation of a `throw` expression with an argument
|
||||
* (e.g. `throw std::bad_alloc()`).
|
||||
*/
|
||||
class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContext {
|
||||
class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableInitialization {
|
||||
TranslatedThrowValueExpr() { not expr instanceof ReThrowExpr }
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getTypeForGLValue(getExceptionType())
|
||||
TranslatedVariableInitialization.super.hasInstruction(opcode, tag, resultType)
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
result = TranslatedThrowExpr.super.getInstructionSuccessor(tag, kind)
|
||||
or
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getInitialization().getFirstInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
result = TranslatedVariableInitialization.super.getInstructionSuccessor(tag, kind)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and
|
||||
result = getInstruction(ThrowTag())
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getIRTempVariable(expr, ThrowTempVar())
|
||||
}
|
||||
final override Instruction getInitializationSuccessor() { result = getInstruction(ThrowTag()) }
|
||||
|
||||
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
tag = ThrowTempVar() and
|
||||
@@ -1985,6 +1967,8 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
|
||||
}
|
||||
|
||||
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
result = TranslatedVariableInitialization.super.getInstructionOperand(tag, operandTag)
|
||||
or
|
||||
tag = ThrowTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
@@ -2001,16 +1985,14 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
|
||||
result = getTypeForPRValue(getExceptionType())
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = getExceptionType() }
|
||||
|
||||
TranslatedInitialization getInitialization() {
|
||||
final override TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(expr.getExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
final override IRVariable getIRVariable() { result = getIRTempVariable(expr, ThrowTempVar()) }
|
||||
|
||||
final override Opcode getThrowOpcode() { result instanceof Opcode::ThrowValue }
|
||||
|
||||
private Type getExceptionType() { result = expr.getType() }
|
||||
|
||||
@@ -30,6 +30,98 @@ abstract class InitializationContext extends TranslatedElement {
|
||||
abstract Type getTargetType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for any element that initializes a stack variable. Examples include local variable
|
||||
* declarations, `return` statements, and `throw` expressions.
|
||||
*/
|
||||
abstract class TranslatedVariableInitialization extends TranslatedElement, InitializationContext {
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getTypeForGLValue(getTargetType())
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getTypeForPRValue(getTargetType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
kind instanceof GotoEdge and
|
||||
if hasUninitializedInstruction()
|
||||
then result = getInstruction(InitializerStoreTag())
|
||||
else result = getInitialization().getFirstInstruction()
|
||||
)
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
kind instanceof GotoEdge and
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
result = getInitialization().getFirstInstruction()
|
||||
or
|
||||
not exists(getInitialization()) and result = getInitializationSuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getInitializationSuccessor()
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
final override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag()
|
||||
or
|
||||
hasUninitializedInstruction() and tag = InitializerStoreTag()
|
||||
) and
|
||||
result = getIRVariable()
|
||||
}
|
||||
|
||||
final override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initialization for the variable.
|
||||
*/
|
||||
abstract TranslatedInitialization getInitialization();
|
||||
|
||||
/**
|
||||
* Get the `IRVariable` to be initialized. This may be an `IRTempVariable`.
|
||||
*/
|
||||
abstract IRVariable getIRVariable();
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` to be executed immediately after the initialization.
|
||||
*/
|
||||
abstract Instruction getInitializationSuccessor();
|
||||
|
||||
/**
|
||||
* Holds if this initialization requires an `Uninitialized` instruction to be emitted before
|
||||
* evaluating the initializer.
|
||||
*/
|
||||
final predicate hasUninitializedInstruction() {
|
||||
not exists(getInitialization()) or
|
||||
getInitialization() instanceof TranslatedListInitialization or
|
||||
getInitialization() instanceof TranslatedConstructorInitialization or
|
||||
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of any initialization, whether from an
|
||||
* initializer list or from a direct initializer.
|
||||
|
||||
@@ -130,46 +130,20 @@ abstract class TranslatedReturnStmt extends TranslatedStmt {
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationContext {
|
||||
class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariableInitialization {
|
||||
TranslatedReturnValueStmt() { stmt.hasExpr() }
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getTypeForGLValue(getEnclosingFunction().getReturnType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getInitialization().getFirstInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and
|
||||
final override Instruction getInitializationSuccessor() {
|
||||
result = getEnclosingFunction().getReturnSuccessorInstruction()
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getEnclosingFunction().getReturnVariable()
|
||||
}
|
||||
final override Type getTargetType() { result = getEnclosingFunction().getReturnType() }
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = getEnclosingFunction().getReturnType() }
|
||||
|
||||
TranslatedInitialization getInitialization() {
|
||||
final override TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(stmt.getExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
final override IRVariable getIRVariable() { result = getEnclosingFunction().getReturnVariable() }
|
||||
}
|
||||
|
||||
class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
|
||||
@@ -947,6 +947,10 @@ class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
|
||||
}
|
||||
|
||||
class CheckedConvertOrNullInstruction extends UnaryInstruction {
|
||||
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts between two addresses
|
||||
* related by inheritance.
|
||||
@@ -987,7 +991,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
|
||||
/**
|
||||
* Represents an instruction that converts from the address of a derived class
|
||||
* to the address of a direct non-virtual base class.
|
||||
* to the address of a base class.
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }
|
||||
@@ -1198,52 +1202,63 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be read
|
||||
* by that call.
|
||||
* An instruction representing the side effect of a function call on any memory
|
||||
* that might be read by that call. This instruction is emitted instead of
|
||||
* `CallSideEffectInstruction` when it's certain that the call target cannot
|
||||
* write to escaped memory.
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a read side effect of a function call on a
|
||||
* specific parameter.
|
||||
*/
|
||||
class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode }
|
||||
|
||||
/** Gets the operand for the value that will be read from this instruction, if known. */
|
||||
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the value that will be read from this instruction, if known. */
|
||||
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }
|
||||
|
||||
/** Gets the operand for the address from which this instruction may read. */
|
||||
final AddressOperand getArgumentOperand() { result = getAnOperand() }
|
||||
|
||||
/** Gets the address from which this instruction may read. */
|
||||
final Instruction getArgumentDef() { result = getArgumentOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class BufferReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction {
|
||||
SizedBufferReadSideEffectInstruction() {
|
||||
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
|
||||
}
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
* An instruction representing a write side effect of a function call on a
|
||||
* specific parameter.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
@@ -2,6 +2,7 @@ private import AliasAnalysisInternal
|
||||
private import cpp
|
||||
private import InputIR
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private import semmle.code.cpp.ir.implementation.IRConfiguration
|
||||
private import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
@@ -95,6 +96,10 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
)
|
||||
or
|
||||
// Conversion using dynamic_cast results in an unknown offset
|
||||
instr instanceof CheckedConvertOrNullInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
@@ -277,9 +282,14 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||
* analysis.
|
||||
*/
|
||||
predicate variableAddressEscapes(IRVariable var) {
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable))
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable))
|
||||
)
|
||||
or
|
||||
// All variables with static storage duration have their address escape.
|
||||
// All variables with static storage duration have their address escape, even when escape analysis
|
||||
// is allowed to be unsound. Otherwise, we won't have a definition for any non-escaped global
|
||||
// variable. Normally, we rely on `AliasedDefinition` to handle that.
|
||||
not var instanceof IRAutomaticVariable
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class PropertyProvider extends IRPropertyProvider {
|
||||
exists(
|
||||
MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap
|
||||
|
|
||||
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and
|
||||
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex) and
|
||||
key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() +
|
||||
"]" and
|
||||
result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() +
|
||||
|
||||
@@ -30,7 +30,7 @@ class InetAton extends TaintFunction, ArrayFunction {
|
||||
}
|
||||
}
|
||||
|
||||
class InetAddr extends TaintFunction, ArrayFunction {
|
||||
class InetAddr extends TaintFunction, ArrayFunction, AliasFunction {
|
||||
InetAddr() { hasGlobalName("inet_addr") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -41,6 +41,12 @@ class InetAddr extends TaintFunction, ArrayFunction {
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
}
|
||||
|
||||
class InetNetwork extends TaintFunction, ArrayFunction {
|
||||
|
||||
@@ -83,6 +83,11 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE
|
||||
override predicate hasOnlySpecificReadSideEffects() { none() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
class PureFunction extends TaintFunction, SideEffectFunction {
|
||||
|
||||
@@ -47,20 +47,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
// These always copy the full value of the input buffer to the output
|
||||
// buffer
|
||||
this.hasName("strcpy") or
|
||||
this.hasName("_mbscpy") or
|
||||
this.hasName("wcscpy")
|
||||
) and
|
||||
(
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1) and
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1) and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
input.isParameter(0) and
|
||||
output.isReturnValue()
|
||||
@@ -77,10 +68,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
|
||||
this.hasName("wcsncpy") or
|
||||
this.hasName("_wcsncpy_l")
|
||||
) and
|
||||
(
|
||||
input.isParameter(2) or
|
||||
input.isParameterDeref(1)
|
||||
) and
|
||||
input.isParameter(2) and
|
||||
(
|
||||
output.isParameterDeref(0) or
|
||||
output.isReturnValueDeref()
|
||||
|
||||
@@ -9,17 +9,14 @@ import semmle.code.cpp.models.interfaces.Taint
|
||||
class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction {
|
||||
StrdupFunction() {
|
||||
exists(string name |
|
||||
hasGlobalOrStdName(name) and
|
||||
hasGlobalName(name) and
|
||||
(
|
||||
// strdup(str)
|
||||
name = "strdup"
|
||||
or
|
||||
// wcsdup(str)
|
||||
name = "wcsdup"
|
||||
)
|
||||
or
|
||||
hasGlobalName(name) and
|
||||
(
|
||||
or
|
||||
// _strdup(str)
|
||||
name = "_strdup"
|
||||
or
|
||||
@@ -37,9 +34,32 @@ class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
// These always copy the full value of the input buffer to the result
|
||||
// buffer
|
||||
input.isParameterDeref(0) and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `strndup` style allocation function.
|
||||
*/
|
||||
class StrndupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction {
|
||||
StrndupFunction() {
|
||||
exists(string name |
|
||||
hasGlobalName(name) and
|
||||
// strndup(str, maxlen)
|
||||
name = "strndup"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
input.isParameterDeref(0) or
|
||||
input.isParameter(1)
|
||||
) and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import FunctionInputsAndOutputs
|
||||
import semmle.code.cpp.models.Models
|
||||
|
||||
/**
|
||||
* A library function for which a value is copied from a parameter or qualifier
|
||||
* to an output buffer, return value, or qualifier.
|
||||
* A library function for which a value is or may be copied from a parameter
|
||||
* or qualifier to an output buffer, return value, or qualifier.
|
||||
*
|
||||
* Note that this does not include partial copying of values or partial writes
|
||||
* to destinations; that is covered by `TaintModel.qll`.
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
* `FormattingFunction` to match the flow within that function.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
private Type stripTopLevelSpecifiersOnly(Type t) {
|
||||
result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType())
|
||||
@@ -39,7 +40,7 @@ private Type getAFormatterWideTypeOrDefault() {
|
||||
/**
|
||||
* A standard library function that uses a `printf`-like formatting string.
|
||||
*/
|
||||
abstract class FormattingFunction extends Function {
|
||||
abstract class FormattingFunction extends ArrayFunction, TaintFunction {
|
||||
/** Gets the position at which the format parameter occurs. */
|
||||
abstract int getFormatParameterIndex();
|
||||
|
||||
@@ -133,4 +134,33 @@ abstract class FormattingFunction extends Function {
|
||||
* Gets the position of the buffer size argument, if any.
|
||||
*/
|
||||
int getSizeParameterIndex() { none() }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) {
|
||||
bufParam = getFormatParameterIndex()
|
||||
}
|
||||
|
||||
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
|
||||
bufParam = getOutputParameterIndex() and
|
||||
countParam = getSizeParameterIndex()
|
||||
}
|
||||
|
||||
override predicate hasArrayWithUnknownSize(int bufParam) {
|
||||
bufParam = getOutputParameterIndex() and
|
||||
not exists(getSizeParameterIndex())
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = getFormatParameterIndex() }
|
||||
|
||||
override predicate hasArrayOutput(int bufParam) { bufParam = getOutputParameterIndex() }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
exists(int arg |
|
||||
(
|
||||
arg = getFormatParameterIndex() or
|
||||
arg >= getFirstFormatArgumentIndex()
|
||||
) and
|
||||
input.isParameterDeref(arg) and
|
||||
output.isParameterDeref(getOutputParameterIndex())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ import semmle.code.cpp.models.Models
|
||||
* from a parameter or qualifier to an output buffer, return value, or qualifier.
|
||||
*
|
||||
* Note that this does not include direct copying of values; that is covered by
|
||||
* DataFlowModel.qll
|
||||
* DataFlowModel.qll. If a value is sometimes copied in full, and sometimes
|
||||
* altered (for example copying a string with `strncpy`), this is also considered
|
||||
* data flow.
|
||||
*/
|
||||
abstract class TaintFunction extends Function {
|
||||
abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output);
|
||||
|
||||
@@ -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(), ", ")
|
||||
@@ -0,0 +1,80 @@
|
||||
int atoi(const char *nptr);
|
||||
char *getenv(const char *name);
|
||||
char *strcat(char * s1, const char * s2);
|
||||
|
||||
char *strdup(const char *);
|
||||
char *_strdup(const char *);
|
||||
char *unmodeled_function(const char *);
|
||||
|
||||
void sink(const char *);
|
||||
void sink(int);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
|
||||
|
||||
sink(_strdup(getenv("VAR")));
|
||||
sink(strdup(getenv("VAR")));
|
||||
sink(unmodeled_function(getenv("VAR")));
|
||||
|
||||
char untainted_buf[100] = "";
|
||||
char buf[100] = "VAR = ";
|
||||
sink(strcat(buf, getenv("VAR")));
|
||||
|
||||
sink(buf); // BUG: no taint
|
||||
sink(untainted_buf); // the two buffers would be conflated if we added flow through partial chi inputs
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef unsigned int inet_addr_retval;
|
||||
inet_addr_retval inet_addr(const char *dotted_address);
|
||||
void sink(inet_addr_retval);
|
||||
|
||||
void test_indirect_arg_to_model() {
|
||||
// This test is non-sensical but carefully arranged so we get data flow into
|
||||
// inet_addr not through the function argument but through its associated
|
||||
// read side effect.
|
||||
void *env_pointer = getenv("VAR"); // env_pointer is tainted, not its data.
|
||||
inet_addr_retval a = inet_addr((const char *)&env_pointer);
|
||||
sink(a);
|
||||
}
|
||||
|
||||
class B {
|
||||
public:
|
||||
virtual void f(const char*) = 0;
|
||||
};
|
||||
|
||||
class D1 : public B {};
|
||||
|
||||
class D2 : public D1 {
|
||||
public:
|
||||
void f(const char* p) override {}
|
||||
};
|
||||
|
||||
class D3 : public D2 {
|
||||
public:
|
||||
void f(const char* p) override {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
void test_dynamic_cast() {
|
||||
B* b = new D3();
|
||||
b->f(getenv("VAR")); // tainted
|
||||
|
||||
((D2*)b)->f(getenv("VAR")); // tainted
|
||||
static_cast<D2*>(b)->f(getenv("VAR")); // tainted
|
||||
dynamic_cast<D2*>(b)->f(getenv("VAR")); // tainted
|
||||
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // tainted
|
||||
|
||||
B* b2 = new D2();
|
||||
b2->f(getenv("VAR"));
|
||||
|
||||
((D2*)b2)->f(getenv("VAR"));
|
||||
static_cast<D2*>(b2)->f(getenv("VAR"));
|
||||
dynamic_cast<D2*>(b2)->f(getenv("VAR"));
|
||||
reinterpret_cast<D2*>(b2)->f(getenv("VAR"));
|
||||
|
||||
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // tainted [FALSE POSITIVE]
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:6:15:6:24 | p#0 |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:21 | call to getenv |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:28 | (const char *)... |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:5:14:5:23 | p#0 |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:13 | call to strdup |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:28 | (const char *)... |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:20 | call to getenv |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:27 | (const char *)... |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:7:26:7:35 | p#0 |
|
||||
| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:32 | call to getenv |
|
||||
| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:39 | (const char *)... |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:38:3:39 | s2 |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:13 | call to strcat |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:25 | call to getenv |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:32 | (const char *)... |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:32:11:32:26 | p#0 |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:30 | call to getenv |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:37 | (void *)... |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:22:39:22 | a |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:26:39:34 | call to inet_addr |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:50:39:61 | & ... |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | p#0 |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:15 | call to getenv |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:22 | (const char *)... |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
|
||||
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
|
||||
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:22 | call to getenv |
|
||||
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:29 | (const char *)... |
|
||||
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
|
||||
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
|
||||
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:33 | call to getenv |
|
||||
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:40 | (const char *)... |
|
||||
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
|
||||
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
|
||||
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:34 | call to getenv |
|
||||
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:41 | (const char *)... |
|
||||
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
|
||||
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
|
||||
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:38 | call to getenv |
|
||||
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:45 | (const char *)... |
|
||||
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | p#0 |
|
||||
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:16 | call to getenv |
|
||||
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:23 | (const char *)... |
|
||||
| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:23 | call to getenv |
|
||||
| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:30 | (const char *)... |
|
||||
| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:34 | call to getenv |
|
||||
| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:41 | (const char *)... |
|
||||
| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:35 | call to getenv |
|
||||
| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:42 | (const char *)... |
|
||||
| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
|
||||
| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:39 | call to getenv |
|
||||
| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:46 | (const char *)... |
|
||||
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
|
||||
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
|
||||
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:35 | call to getenv |
|
||||
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:42 | (const char *)... |
|
||||
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:92:10:92:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv |
|
||||
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... |
|
||||
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | access to array |
|
||||
| test_diff.cpp:94:32:94:35 | argv | defaulttainttracking.cpp:10:11:10:13 | p#0 |
|
||||
| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:2:11:2:13 | p#0 |
|
||||
| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:10:94:36 | reinterpret_cast<int>... |
|
||||
| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:32:94:35 | argv |
|
||||
| test_diff.cpp:96:26:96:29 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:16:39:16:39 | a |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:17:10:17:10 | a |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:29 | argv |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | (const char *)... |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | access to array |
|
||||
| test_diff.cpp:98:18:98:21 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:16:39:16:39 | a |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:17:10:17:10 | a |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:13:98:13 | p |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:17:98:21 | & ... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:18:98:21 | argv |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:10:100:14 | (const char *)... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:10:100:14 | * ... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:11:100:11 | p |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:11:100:14 | access to array |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | (const char *)... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | * ... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:27 | p |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:30 | access to array |
|
||||
| test_diff.cpp:104:12:104:15 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | (const char *)... |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | * ... |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:15 | argv |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:19 | ... + ... |
|
||||
| test_diff.cpp:108:10:108:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:29:24:29:24 | p |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:30:14:30:14 | p |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:13 | argv |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | (const char *)... |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | access to array |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:36:24:36:24 | p |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:13 | argv |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | (const char *)... |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | access to array |
|
||||
| test_diff.cpp:115:11:115:14 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:41:24:41:24 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:42:14:42:14 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:52:24:52:24 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:53:37:53:37 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:14 | argv |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | (const char *)... |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | access to array |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:60:24:60:24 | p |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:61:34:61:34 | p |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:88:24:88:24 | p |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:29 | argv |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | (const char *)... |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | access to array |
|
||||
| test_diff.cpp:121:23:121:26 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:60:24:60:24 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:61:34:61:34 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:67:24:67:24 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:68:14:68:14 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:26 | argv |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | (const char *)... |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | access to array |
|
||||
| test_diff.cpp:124:19:124:22 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:81:24:81:24 | p |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:82:14:82:14 | p |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:22 | argv |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | (const char *)... |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | access to array |
|
||||
| test_diff.cpp:126:43:126:46 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:76:24:76:24 | p |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:81:24:81:24 | p |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:82:14:82:14 | p |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:46 | argv |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | (const char *)... |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | access to array |
|
||||
| test_diff.cpp:128:44:128:47 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:76:24:76:24 | p |
|
||||
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:81:24:81:24 | p |
|
||||
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:82:14:82:14 | p |
|
||||
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:47 | argv |
|
||||
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:50 | (const char *)... |
|
||||
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:50 | access to array |
|
||||
@@ -0,0 +1,5 @@
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking
|
||||
|
||||
from Expr source, Element tainted
|
||||
where tainted(source, tainted)
|
||||
select source, tainted
|
||||
@@ -0,0 +1,129 @@
|
||||
void sink(const char *);
|
||||
void sink(int);
|
||||
|
||||
struct S {
|
||||
void(*f)(const char*);
|
||||
|
||||
void apply(char* p) {
|
||||
f(p);
|
||||
}
|
||||
|
||||
void (*get())(const char*) {
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
void calls_sink_with_argv(const char* a) {
|
||||
sink(a);
|
||||
}
|
||||
|
||||
extern int i;
|
||||
|
||||
class BaseWithPureVirtual {
|
||||
public:
|
||||
virtual void f(const char*) = 0;
|
||||
};
|
||||
|
||||
class DerivedCallsSink : public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class DerivedDoesNotCallSink : public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {}
|
||||
};
|
||||
|
||||
class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class DerivedDoesNotCallSinkDiamond2 : virtual public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {}
|
||||
};
|
||||
|
||||
class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCallSinkDiamond2 {
|
||||
void f(const char* p) override {
|
||||
DerivedCallsSinkDiamond1::f(p);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class CRTP {
|
||||
public:
|
||||
void f(const char* p) {
|
||||
static_cast<T*>(this)->g(p);
|
||||
}
|
||||
};
|
||||
|
||||
class CRTPCallsSink : public CRTP<CRTPCallsSink> {
|
||||
public:
|
||||
void g(const char* p) {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class Derived1 : public BaseWithPureVirtual {};
|
||||
|
||||
class Derived2 : public Derived1 {
|
||||
public:
|
||||
void f(const char* p) override {}
|
||||
};
|
||||
|
||||
class Derived3 : public Derived2 {
|
||||
public:
|
||||
void f(const char* p) override {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class CRTPDoesNotCallSink : public CRTP<CRTPDoesNotCallSink> {
|
||||
public:
|
||||
void g(const char* p) {}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
sink(argv[0]);
|
||||
|
||||
sink(reinterpret_cast<int>(argv));
|
||||
|
||||
calls_sink_with_argv(argv[1]);
|
||||
|
||||
char*** p = &argv;
|
||||
|
||||
sink(*p[0]);
|
||||
|
||||
calls_sink_with_argv(*p[i]);
|
||||
|
||||
sink(*(argv + 1));
|
||||
|
||||
BaseWithPureVirtual* b = new DerivedCallsSink;
|
||||
|
||||
b->f(argv[1]);
|
||||
|
||||
b = new DerivedDoesNotCallSink;
|
||||
b->f(argv[0]); // no flow [FALSE POSITIVE by AST]
|
||||
|
||||
BaseWithPureVirtual* b2 = new DerivesMultiple;
|
||||
|
||||
b2->f(argv[i]);
|
||||
|
||||
CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
|
||||
crtp_not_call_sink.f(argv[0]);
|
||||
|
||||
CRTP<CRTPCallsSink> crtp_calls_sink;
|
||||
crtp_calls_sink.f(argv[0]);
|
||||
|
||||
Derived1* calls_sink = new Derived3;
|
||||
calls_sink->f(argv[1]);
|
||||
|
||||
static_cast<Derived2*>(calls_sink)->f(argv[1]);
|
||||
|
||||
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // flow [NOT DETECTED by IR]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup | IR only |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... | IR only |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:21:3:22 | s1 | AST only |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:21:8:21:10 | buf | AST only |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:15:22:17 | buf | AST only |
|
||||
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf | AST only |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address | AST only |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | AST only |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:51:39:61 | env_pointer | AST only |
|
||||
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | IR only |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only |
|
||||
| test_diff.cpp:111:10:111:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | AST only |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | AST only |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:29:24:29:24 | p | AST only |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:30:14:30:14 | p | AST only |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p | IR only |
|
||||
@@ -0,0 +1,19 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.security.TaintTracking as ASTTaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
|
||||
|
||||
predicate astFlow(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
|
||||
|
||||
predicate irFlow(Expr source, Element sink) { IRDefaultTaintTracking::tainted(source, sink) }
|
||||
|
||||
from Expr source, Element sink, string note
|
||||
where
|
||||
astFlow(source, sink) and
|
||||
not irFlow(source, sink) and
|
||||
note = "AST only"
|
||||
or
|
||||
irFlow(source, sink) and
|
||||
not astFlow(source, sink) and
|
||||
note = "IR only"
|
||||
select source, sink, note
|
||||
@@ -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]
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only |
|
||||
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:64:14:64:14 | AST only |
|
||||
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:66:14:66:14 | AST only |
|
||||
| clang.cpp:12:9:12:20 | clang.cpp:18:8:18:19 | AST only |
|
||||
| clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only |
|
||||
| clang.cpp:28:27:28:32 | clang.cpp:29:27:29:28 | AST only |
|
||||
| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only |
|
||||
@@ -18,11 +17,12 @@
|
||||
| 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 |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:29:3:29:6 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:35:8:35:8 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:41:8:41:8 | AST only |
|
||||
| lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only |
|
||||
| ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only |
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
| BarrierGuard.cpp:55:13:55:13 | x | BarrierGuard.cpp:49:10:49:15 | call to source |
|
||||
| acrossLinkTargets.cpp:12:8:12:8 | (int)... | acrossLinkTargets.cpp:19:27:19:32 | call to source |
|
||||
| acrossLinkTargets.cpp:12:8:12:8 | x | acrossLinkTargets.cpp:19:27:19:32 | call to source |
|
||||
| clang.cpp:18:8:18:19 | (const int *)... | clang.cpp:12:9:12:20 | sourceArray1 |
|
||||
| clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 |
|
||||
| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
|
||||
| clang.cpp:41:18:41:19 | m2 | clang.cpp:39:42:39:47 | call to source |
|
||||
| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
|
||||
@@ -28,6 +30,9 @@
|
||||
| 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 |
|
||||
| test.cpp:10:8:10:9 | t2 | 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()
|
||||
}
|
||||
}
|
||||
|
||||
134
cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp
Normal file
134
cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef struct {} FILE;
|
||||
|
||||
int snprintf(char *s, size_t n, const char *format, ...);
|
||||
int sprintf(char *s, const char *format, ...);
|
||||
int swprintf(wchar_t *s, size_t n, const wchar_t *format, ...);
|
||||
|
||||
typedef void *va_list;
|
||||
#define va_start(ap, parmN)
|
||||
#define va_end(ap)
|
||||
#define va_arg(ap, type) ((type)0)
|
||||
|
||||
int vsnprintf(char *s, size_t n, const char *format, va_list arg);
|
||||
|
||||
int mysprintf(char *s, size_t n, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(s, n, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int sscanf(const char *s, const char *format, ...);
|
||||
|
||||
// ----------
|
||||
|
||||
int source();
|
||||
void sink(...) {};
|
||||
|
||||
namespace string
|
||||
{
|
||||
char *source();
|
||||
};
|
||||
|
||||
namespace wstring
|
||||
{
|
||||
wchar_t *source();
|
||||
};
|
||||
|
||||
// ----------
|
||||
|
||||
void test1()
|
||||
{
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%s", "Hello."));
|
||||
sink(buffer);
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%s", string::source()));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, string::source(), "Hello."));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%s %s %s", "a", "b", string::source()));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%.*s", 10, string::source()));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%i", 0));
|
||||
sink(buffer);
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%i", source()));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%.*s", source(), "Hello."));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(snprintf(buffer, 256, "%p", string::source()));
|
||||
sink(buffer); // tainted (debatable)
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(sprintf(buffer, "%s", string::source()));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(sprintf(buffer, "%ls", wstring::source()));
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
{
|
||||
wchar_t wbuffer[256] = {0};
|
||||
sink(swprintf(wbuffer, 256, L"%s", wstring::source()));
|
||||
sink(wbuffer); // tainted
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(mysprintf(buffer, 256, "%s", string::source()));
|
||||
sink(buffer); // tainted [NOT DETECTED - implement UserDefinedFormattingFunction.getOutputParameterIndex()]
|
||||
}
|
||||
|
||||
{
|
||||
int i = 0;
|
||||
sink(sscanf("123", "%i", &i));
|
||||
sink(i);
|
||||
}
|
||||
{
|
||||
int i = 0;
|
||||
sink(sscanf(string::source(), "%i", &i));
|
||||
sink(i); // tainted [NOT DETECTED]
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(sscanf("Hello.", "%s", &buffer));
|
||||
sink(buffer);
|
||||
}
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(sscanf(string::source(), "%s", &buffer));
|
||||
sink(buffer); // tainted [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,108 @@
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
|
||||
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
|
||||
| format.cpp:16:21:16:21 | s | format.cpp:20:13:20:13 | s | |
|
||||
| format.cpp:16:31:16:31 | n | format.cpp:20:16:20:16 | n | |
|
||||
| format.cpp:16:46:16:51 | format | format.cpp:20:19:20:24 | format | |
|
||||
| format.cpp:18:10:18:13 | args | format.cpp:20:27:20:30 | args | |
|
||||
| format.cpp:46:21:46:24 | {...} | format.cpp:47:17:47:22 | buffer | |
|
||||
| format.cpp:46:21:46:24 | {...} | format.cpp:48:8:48:13 | buffer | |
|
||||
| format.cpp:46:23:46:23 | 0 | format.cpp:46:21:46:24 | {...} | TAINT |
|
||||
| format.cpp:47:17:47:22 | ref arg buffer | format.cpp:48:8:48:13 | buffer | |
|
||||
| format.cpp:47:30:47:33 | %s | format.cpp:47:17:47:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:47:36:47:43 | Hello. | format.cpp:47:17:47:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:51:21:51:24 | {...} | format.cpp:52:17:52:22 | buffer | |
|
||||
| format.cpp:51:21:51:24 | {...} | format.cpp:53:8:53:13 | buffer | |
|
||||
| format.cpp:51:23:51:23 | 0 | format.cpp:51:21:51:24 | {...} | TAINT |
|
||||
| format.cpp:52:17:52:22 | ref arg buffer | format.cpp:53:8:53:13 | buffer | |
|
||||
| format.cpp:52:30:52:33 | %s | format.cpp:52:17:52:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:52:36:52:49 | call to source | format.cpp:52:17:52:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:56:21:56:24 | {...} | format.cpp:57:17:57:22 | buffer | |
|
||||
| format.cpp:56:21:56:24 | {...} | format.cpp:58:8:58:13 | buffer | |
|
||||
| format.cpp:56:23:56:23 | 0 | format.cpp:56:21:56:24 | {...} | TAINT |
|
||||
| format.cpp:57:17:57:22 | ref arg buffer | format.cpp:58:8:58:13 | buffer | |
|
||||
| format.cpp:57:30:57:43 | call to source | format.cpp:57:17:57:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:57:48:57:55 | Hello. | format.cpp:57:17:57:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:61:21:61:24 | {...} | format.cpp:62:17:62:22 | buffer | |
|
||||
| format.cpp:61:21:61:24 | {...} | format.cpp:63:8:63:13 | buffer | |
|
||||
| format.cpp:61:23:61:23 | 0 | format.cpp:61:21:61:24 | {...} | TAINT |
|
||||
| format.cpp:62:17:62:22 | ref arg buffer | format.cpp:63:8:63:13 | buffer | |
|
||||
| format.cpp:62:30:62:39 | %s %s %s | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:62:42:62:44 | a | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:62:47:62:49 | b | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:62:52:62:65 | call to source | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:66:21:66:24 | {...} | format.cpp:67:17:67:22 | buffer | |
|
||||
| format.cpp:66:21:66:24 | {...} | format.cpp:68:8:68:13 | buffer | |
|
||||
| format.cpp:66:23:66:23 | 0 | format.cpp:66:21:66:24 | {...} | TAINT |
|
||||
| format.cpp:67:17:67:22 | ref arg buffer | format.cpp:68:8:68:13 | buffer | |
|
||||
| format.cpp:67:30:67:35 | %.*s | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:67:38:67:39 | 10 | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:67:42:67:55 | call to source | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:72:21:72:24 | {...} | format.cpp:73:17:73:22 | buffer | |
|
||||
| format.cpp:72:21:72:24 | {...} | format.cpp:74:8:74:13 | buffer | |
|
||||
| format.cpp:72:23:72:23 | 0 | format.cpp:72:21:72:24 | {...} | TAINT |
|
||||
| format.cpp:73:17:73:22 | ref arg buffer | format.cpp:74:8:74:13 | buffer | |
|
||||
| format.cpp:73:30:73:33 | %i | format.cpp:73:17:73:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:73:36:73:36 | 0 | format.cpp:73:17:73:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:77:21:77:24 | {...} | format.cpp:78:17:78:22 | buffer | |
|
||||
| format.cpp:77:21:77:24 | {...} | format.cpp:79:8:79:13 | buffer | |
|
||||
| format.cpp:77:23:77:23 | 0 | format.cpp:77:21:77:24 | {...} | TAINT |
|
||||
| format.cpp:78:17:78:22 | ref arg buffer | format.cpp:79:8:79:13 | buffer | |
|
||||
| format.cpp:78:30:78:33 | %i | format.cpp:78:17:78:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:78:36:78:41 | call to source | format.cpp:78:17:78:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:82:21:82:24 | {...} | format.cpp:83:17:83:22 | buffer | |
|
||||
| format.cpp:82:21:82:24 | {...} | format.cpp:84:8:84:13 | buffer | |
|
||||
| format.cpp:82:23:82:23 | 0 | format.cpp:82:21:82:24 | {...} | TAINT |
|
||||
| format.cpp:83:17:83:22 | ref arg buffer | format.cpp:84:8:84:13 | buffer | |
|
||||
| format.cpp:83:30:83:35 | %.*s | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:83:38:83:43 | call to source | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:83:48:83:55 | Hello. | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:88:21:88:24 | {...} | format.cpp:89:17:89:22 | buffer | |
|
||||
| format.cpp:88:21:88:24 | {...} | format.cpp:90:8:90:13 | buffer | |
|
||||
| format.cpp:88:23:88:23 | 0 | format.cpp:88:21:88:24 | {...} | TAINT |
|
||||
| format.cpp:89:17:89:22 | ref arg buffer | format.cpp:90:8:90:13 | buffer | |
|
||||
| format.cpp:89:30:89:33 | %p | format.cpp:89:17:89:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:89:36:89:49 | call to source | format.cpp:89:17:89:22 | ref arg buffer | TAINT |
|
||||
| format.cpp:94:21:94:24 | {...} | format.cpp:95:16:95:21 | buffer | |
|
||||
| format.cpp:94:21:94:24 | {...} | format.cpp:96:8:96:13 | buffer | |
|
||||
| format.cpp:94:23:94:23 | 0 | format.cpp:94:21:94:24 | {...} | TAINT |
|
||||
| format.cpp:95:16:95:21 | ref arg buffer | format.cpp:96:8:96:13 | buffer | |
|
||||
| format.cpp:95:24:95:27 | %s | format.cpp:95:16:95:21 | ref arg buffer | TAINT |
|
||||
| format.cpp:95:30:95:43 | call to source | format.cpp:95:16:95:21 | ref arg buffer | TAINT |
|
||||
| format.cpp:99:21:99:24 | {...} | format.cpp:100:16:100:21 | buffer | |
|
||||
| format.cpp:99:21:99:24 | {...} | format.cpp:101:8:101:13 | buffer | |
|
||||
| format.cpp:99:23:99:23 | 0 | format.cpp:99:21:99:24 | {...} | TAINT |
|
||||
| format.cpp:100:16:100:21 | ref arg buffer | format.cpp:101:8:101:13 | buffer | |
|
||||
| format.cpp:100:24:100:28 | %ls | format.cpp:100:16:100:21 | ref arg buffer | TAINT |
|
||||
| format.cpp:100:31:100:45 | call to source | format.cpp:100:16:100:21 | ref arg buffer | TAINT |
|
||||
| format.cpp:104:25:104:28 | {...} | format.cpp:105:17:105:23 | wbuffer | |
|
||||
| format.cpp:104:25:104:28 | {...} | format.cpp:106:8:106:14 | wbuffer | |
|
||||
| format.cpp:104:27:104:27 | 0 | format.cpp:104:25:104:28 | {...} | TAINT |
|
||||
| format.cpp:105:17:105:23 | ref arg wbuffer | format.cpp:106:8:106:14 | wbuffer | |
|
||||
| format.cpp:105:31:105:35 | %s | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT |
|
||||
| format.cpp:105:38:105:52 | call to source | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT |
|
||||
| format.cpp:109:21:109:24 | {...} | format.cpp:110:18:110:23 | buffer | |
|
||||
| format.cpp:109:21:109:24 | {...} | format.cpp:111:8:111:13 | buffer | |
|
||||
| format.cpp:109:23:109:23 | 0 | format.cpp:109:21:109:24 | {...} | TAINT |
|
||||
| format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | |
|
||||
| format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | |
|
||||
| format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | |
|
||||
| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | |
|
||||
| format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | |
|
||||
| format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | |
|
||||
| format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | |
|
||||
| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | |
|
||||
| format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | |
|
||||
| format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | |
|
||||
| format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | |
|
||||
| format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT |
|
||||
| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | |
|
||||
| format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | |
|
||||
| format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | |
|
||||
| format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | |
|
||||
| format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT |
|
||||
| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | |
|
||||
| format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | |
|
||||
| taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | |
|
||||
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | |
|
||||
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | |
|
||||
@@ -337,9 +439,13 @@
|
||||
| taint.cpp:370:13:370:26 | hello, world | taint.cpp:370:6:370:11 | call to strdup | TAINT |
|
||||
| taint.cpp:371:6:371:12 | call to strndup | taint.cpp:371:2:371:25 | ... = ... | |
|
||||
| taint.cpp:371:6:371:12 | call to strndup | taint.cpp:374:7:374:7 | c | |
|
||||
| taint.cpp:371:14:371:19 | source | taint.cpp:371:6:371:12 | call to strndup | TAINT |
|
||||
| taint.cpp:371:22:371:24 | 100 | taint.cpp:371:6:371:12 | call to strndup | TAINT |
|
||||
| taint.cpp:377:23:377:28 | source | taint.cpp:381:30:381:35 | source | |
|
||||
| taint.cpp:381:6:381:12 | call to strndup | taint.cpp:381:2:381:36 | ... = ... | |
|
||||
| taint.cpp:381:6:381:12 | call to strndup | taint.cpp:382:7:382:7 | a | |
|
||||
| taint.cpp:381:14:381:27 | hello, world | taint.cpp:381:6:381:12 | call to strndup | TAINT |
|
||||
| taint.cpp:381:30:381:35 | source | taint.cpp:381:6:381:12 | call to strndup | TAINT |
|
||||
| taint.cpp:385:27:385:32 | source | taint.cpp:389:13:389:18 | source | |
|
||||
| taint.cpp:389:6:389:11 | call to wcsdup | taint.cpp:389:2:389:19 | ... = ... | |
|
||||
| taint.cpp:389:6:389:11 | call to wcsdup | taint.cpp:391:7:391:7 | a | |
|
||||
@@ -347,3 +453,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 | |
|
||||
|
||||
@@ -371,7 +371,7 @@ void test_strdup(char *source)
|
||||
c = strndup(source, 100);
|
||||
sink(a); // tainted
|
||||
sink(b);
|
||||
sink(c); // tainted [NOT DETECTED]
|
||||
sink(c); // tainted
|
||||
}
|
||||
|
||||
void test_strndup(int source)
|
||||
@@ -379,7 +379,7 @@ void test_strndup(int source)
|
||||
char *a;
|
||||
|
||||
a = strndup("hello, world", source);
|
||||
sink(a);
|
||||
sink(a); // tainted
|
||||
}
|
||||
|
||||
void test_wcsdup(wchar_t *source)
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
| format.cpp:53:8:53:13 | buffer | format.cpp:52:36:52:49 | call to source |
|
||||
| format.cpp:58:8:58:13 | buffer | format.cpp:57:30:57:43 | call to source |
|
||||
| format.cpp:63:8:63:13 | buffer | format.cpp:62:52:62:65 | call to source |
|
||||
| format.cpp:68:8:68:13 | buffer | format.cpp:67:42:67:55 | call to source |
|
||||
| format.cpp:79:8:79:13 | buffer | format.cpp:78:36:78:41 | call to source |
|
||||
| format.cpp:84:8:84:13 | buffer | format.cpp:83:38:83:43 | call to source |
|
||||
| format.cpp:90:8:90:13 | buffer | format.cpp:89:36:89:49 | call to source |
|
||||
| format.cpp:96:8:96:13 | buffer | format.cpp:95:30:95:43 | call to source |
|
||||
| format.cpp:101:8:101:13 | buffer | format.cpp:100:31:100:45 | call to source |
|
||||
| format.cpp:106:8:106:14 | wbuffer | format.cpp:105:38:105:52 | call to source |
|
||||
| taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 |
|
||||
| taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source |
|
||||
| taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source |
|
||||
@@ -38,4 +48,13 @@
|
||||
| taint.cpp:351:7:351:7 | a | taint.cpp:330:6:330:11 | call to source |
|
||||
| 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:374:7:374:7 | c | taint.cpp:365:24:365:29 | source |
|
||||
| taint.cpp:382:7:382:7 | a | taint.cpp:377:23:377:28 | 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 |
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
| format.cpp:53:8:53:13 | format.cpp:52:36:52:49 | AST only |
|
||||
| format.cpp:58:8:58:13 | format.cpp:57:30:57:43 | AST only |
|
||||
| format.cpp:63:8:63:13 | format.cpp:62:52:62:65 | AST only |
|
||||
| format.cpp:68:8:68:13 | format.cpp:67:42:67:55 | AST only |
|
||||
| format.cpp:79:8:79:13 | format.cpp:78:36:78:41 | AST only |
|
||||
| format.cpp:84:8:84:13 | format.cpp:83:38:83:43 | AST only |
|
||||
| format.cpp:90:8:90:13 | format.cpp:89:36:89:49 | AST only |
|
||||
| format.cpp:96:8:96:13 | format.cpp:95:30:95:43 | AST only |
|
||||
| format.cpp:101:8:101:13 | format.cpp:100:31:100:45 | AST only |
|
||||
| format.cpp:106:8:106:14 | format.cpp:105:38:105:52 | AST only |
|
||||
| taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only |
|
||||
| taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only |
|
||||
| taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only |
|
||||
@@ -13,16 +23,23 @@
|
||||
| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only |
|
||||
| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only |
|
||||
| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only |
|
||||
| taint.cpp:215:7:215:7 | taint.cpp:207:6:207:11 | AST only |
|
||||
| taint.cpp:216:7:216:7 | taint.cpp:207:6:207:11 | AST only |
|
||||
| taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:250:8:250:8 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only |
|
||||
| taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only |
|
||||
| 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:374:7:374:7 | taint.cpp:365:24:365:29 | AST only |
|
||||
| taint.cpp:382:7:382:7 | taint.cpp:377:23:377:28 | 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: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 |
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
| taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source |
|
||||
| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source |
|
||||
| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source |
|
||||
| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source |
|
||||
| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source |
|
||||
| taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source |
|
||||
| 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 |
|
||||
| taint.cpp:430:9:430:14 | member | 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,6 +1,7 @@
|
||||
import default
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.AliasAnalysis
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
|
||||
predicate shouldEscape(IRAutomaticUserVariable var) {
|
||||
exists(string name |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import default
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
|
||||
predicate shouldEscape(IRAutomaticUserVariable var) {
|
||||
exists(string name |
|
||||
|
||||
@@ -8056,6 +8056,20 @@ ir.cpp:
|
||||
# 1166| 0: [VariableAccess] y
|
||||
# 1166| Type = [IntType] int
|
||||
# 1166| ValueCategory = prvalue(load)
|
||||
# 1169| [TopLevelFunction] String ReturnObjectImpl()
|
||||
# 1169| params:
|
||||
# 1169| body: [Block] { ... }
|
||||
# 1170| 0: [ReturnStmt] return ...
|
||||
# 1170| 0: [ConstructorCall] call to String
|
||||
# 1170| Type = [Struct] String
|
||||
# 1170| ValueCategory = prvalue
|
||||
# 1170| 0: [ArrayToPointerConversion] array to pointer conversion
|
||||
# 1170| Type = [PointerType] const char *
|
||||
# 1170| ValueCategory = prvalue
|
||||
# 1170| expr: foo
|
||||
# 1170| Type = [ArrayType] const char[4]
|
||||
# 1170| Value = [StringLiteral] "foo"
|
||||
# 1170| ValueCategory = lvalue
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| params:
|
||||
|
||||
2
cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql
Normal file
2
cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql
Normal file
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
@@ -0,0 +1,26 @@
|
||||
missingOperand
|
||||
| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
@@ -0,0 +1,2 @@
|
||||
multipleOperandMemoryLocations
|
||||
missingVirtualVariableForMemoryLocation
|
||||
@@ -1166,4 +1166,8 @@ int ModeledCallTarget(int x) {
|
||||
return y;
|
||||
}
|
||||
|
||||
String ReturnObjectImpl() {
|
||||
return String("foo");
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -3377,15 +3377,16 @@ ir.cpp:
|
||||
|
||||
# 731| Block 7
|
||||
# 731| r731_11(glval<String>) = VariableAddress[#throw731:19] :
|
||||
# 731| r731_12(glval<unknown>) = FunctionAddress[String] :
|
||||
# 731| r731_13(glval<char[14]>) = StringConstant["String object"] :
|
||||
# 731| r731_14(char *) = Convert : r731_13
|
||||
# 731| v731_15(void) = Call : func:r731_12, this:r731_11, 0:r731_14
|
||||
# 731| mu731_16(unknown) = ^CallSideEffect : ~mu724_3
|
||||
# 731| mu731_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r731_11
|
||||
# 731| v731_18(void) = ^BufferReadSideEffect[0] : &:r731_14, ~mu724_3
|
||||
# 731| mu731_19(unknown) = ^BufferMayWriteSideEffect[0] : &:r731_14
|
||||
# 731| v731_20(void) = ThrowValue : &:r731_11, ~mu724_3
|
||||
# 731| mu731_12(String) = Uninitialized[#throw731:19] : &:r731_11
|
||||
# 731| r731_13(glval<unknown>) = FunctionAddress[String] :
|
||||
# 731| r731_14(glval<char[14]>) = StringConstant["String object"] :
|
||||
# 731| r731_15(char *) = Convert : r731_14
|
||||
# 731| v731_16(void) = Call : func:r731_13, this:r731_11, 0:r731_15
|
||||
# 731| mu731_17(unknown) = ^CallSideEffect : ~mu724_3
|
||||
# 731| mu731_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r731_11
|
||||
# 731| v731_19(void) = ^BufferReadSideEffect[0] : &:r731_15, ~mu724_3
|
||||
# 731| mu731_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r731_15
|
||||
# 731| v731_21(void) = ThrowValue : &:r731_11, ~mu724_3
|
||||
#-----| Exception -> Block 9
|
||||
|
||||
# 733| Block 8
|
||||
@@ -3405,15 +3406,16 @@ ir.cpp:
|
||||
# 735| r735_4(char *) = Load : &:r735_2, ~mu735_3
|
||||
# 735| mu735_5(unknown) = InitializeIndirection[s] : &:r735_4
|
||||
# 736| r736_1(glval<String>) = VariableAddress[#throw736:5] :
|
||||
# 736| r736_2(glval<unknown>) = FunctionAddress[String] :
|
||||
# 736| r736_3(glval<char *>) = VariableAddress[s] :
|
||||
# 736| r736_4(char *) = Load : &:r736_3, ~mu724_3
|
||||
# 736| v736_5(void) = Call : func:r736_2, this:r736_1, 0:r736_4
|
||||
# 736| mu736_6(unknown) = ^CallSideEffect : ~mu724_3
|
||||
# 736| mu736_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r736_1
|
||||
# 736| v736_8(void) = ^BufferReadSideEffect[0] : &:r736_4, ~mu724_3
|
||||
# 736| mu736_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r736_4
|
||||
# 736| v736_10(void) = ThrowValue : &:r736_1, ~mu724_3
|
||||
# 736| mu736_2(String) = Uninitialized[#throw736:5] : &:r736_1
|
||||
# 736| r736_3(glval<unknown>) = FunctionAddress[String] :
|
||||
# 736| r736_4(glval<char *>) = VariableAddress[s] :
|
||||
# 736| r736_5(char *) = Load : &:r736_4, ~mu724_3
|
||||
# 736| v736_6(void) = Call : func:r736_3, this:r736_1, 0:r736_5
|
||||
# 736| mu736_7(unknown) = ^CallSideEffect : ~mu724_3
|
||||
# 736| mu736_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r736_1
|
||||
# 736| v736_9(void) = ^BufferReadSideEffect[0] : &:r736_5, ~mu724_3
|
||||
# 736| mu736_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r736_5
|
||||
# 736| v736_11(void) = ThrowValue : &:r736_1, ~mu724_3
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 738| Block 11
|
||||
@@ -5734,15 +5736,16 @@ ir.cpp:
|
||||
|
||||
# 1140| Block 7
|
||||
# 1140| r1140_11(glval<String>) = VariableAddress[#throw1140:19] :
|
||||
# 1140| r1140_12(glval<unknown>) = FunctionAddress[String] :
|
||||
# 1140| r1140_13(glval<char[14]>) = StringConstant["String object"] :
|
||||
# 1140| r1140_14(char *) = Convert : r1140_13
|
||||
# 1140| v1140_15(void) = Call : func:r1140_12, this:r1140_11, 0:r1140_14
|
||||
# 1140| mu1140_16(unknown) = ^CallSideEffect : ~mu1133_3
|
||||
# 1140| mu1140_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r1140_11
|
||||
# 1140| v1140_18(void) = ^BufferReadSideEffect[0] : &:r1140_14, ~mu1133_3
|
||||
# 1140| mu1140_19(unknown) = ^BufferMayWriteSideEffect[0] : &:r1140_14
|
||||
# 1140| v1140_20(void) = ThrowValue : &:r1140_11, ~mu1133_3
|
||||
# 1140| mu1140_12(String) = Uninitialized[#throw1140:19] : &:r1140_11
|
||||
# 1140| r1140_13(glval<unknown>) = FunctionAddress[String] :
|
||||
# 1140| r1140_14(glval<char[14]>) = StringConstant["String object"] :
|
||||
# 1140| r1140_15(char *) = Convert : r1140_14
|
||||
# 1140| v1140_16(void) = Call : func:r1140_13, this:r1140_11, 0:r1140_15
|
||||
# 1140| mu1140_17(unknown) = ^CallSideEffect : ~mu1133_3
|
||||
# 1140| mu1140_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r1140_11
|
||||
# 1140| v1140_19(void) = ^BufferReadSideEffect[0] : &:r1140_15, ~mu1133_3
|
||||
# 1140| mu1140_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r1140_15
|
||||
# 1140| v1140_21(void) = ThrowValue : &:r1140_11, ~mu1133_3
|
||||
#-----| Exception -> Block 9
|
||||
|
||||
# 1142| Block 8
|
||||
@@ -5762,15 +5765,16 @@ ir.cpp:
|
||||
# 1144| r1144_4(char *) = Load : &:r1144_2, ~mu1144_3
|
||||
# 1144| mu1144_5(unknown) = InitializeIndirection[s] : &:r1144_4
|
||||
# 1145| r1145_1(glval<String>) = VariableAddress[#throw1145:5] :
|
||||
# 1145| r1145_2(glval<unknown>) = FunctionAddress[String] :
|
||||
# 1145| r1145_3(glval<char *>) = VariableAddress[s] :
|
||||
# 1145| r1145_4(char *) = Load : &:r1145_3, ~mu1133_3
|
||||
# 1145| v1145_5(void) = Call : func:r1145_2, this:r1145_1, 0:r1145_4
|
||||
# 1145| mu1145_6(unknown) = ^CallSideEffect : ~mu1133_3
|
||||
# 1145| mu1145_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r1145_1
|
||||
# 1145| v1145_8(void) = ^BufferReadSideEffect[0] : &:r1145_4, ~mu1133_3
|
||||
# 1145| mu1145_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1145_4
|
||||
# 1145| v1145_10(void) = ThrowValue : &:r1145_1, ~mu1133_3
|
||||
# 1145| mu1145_2(String) = Uninitialized[#throw1145:5] : &:r1145_1
|
||||
# 1145| r1145_3(glval<unknown>) = FunctionAddress[String] :
|
||||
# 1145| r1145_4(glval<char *>) = VariableAddress[s] :
|
||||
# 1145| r1145_5(char *) = Load : &:r1145_4, ~mu1133_3
|
||||
# 1145| v1145_6(void) = Call : func:r1145_3, this:r1145_1, 0:r1145_5
|
||||
# 1145| mu1145_7(unknown) = ^CallSideEffect : ~mu1133_3
|
||||
# 1145| mu1145_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1145_1
|
||||
# 1145| v1145_9(void) = ^BufferReadSideEffect[0] : &:r1145_5, ~mu1133_3
|
||||
# 1145| mu1145_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1145_5
|
||||
# 1145| v1145_11(void) = ThrowValue : &:r1145_1, ~mu1133_3
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 1147| Block 11
|
||||
@@ -5884,6 +5888,27 @@ ir.cpp:
|
||||
# 1163| v1163_9(void) = AliasedUse : ~mu1163_3
|
||||
# 1163| v1163_10(void) = ExitFunction :
|
||||
|
||||
# 1169| String ReturnObjectImpl()
|
||||
# 1169| Block 0
|
||||
# 1169| v1169_1(void) = EnterFunction :
|
||||
# 1169| mu1169_2(unknown) = AliasedDefinition :
|
||||
# 1169| mu1169_3(unknown) = UnmodeledDefinition :
|
||||
# 1170| r1170_1(glval<String>) = VariableAddress[#return] :
|
||||
# 1170| mu1170_2(String) = Uninitialized[#return] : &:r1170_1
|
||||
# 1170| r1170_3(glval<unknown>) = FunctionAddress[String] :
|
||||
# 1170| r1170_4(glval<char[4]>) = StringConstant["foo"] :
|
||||
# 1170| r1170_5(char *) = Convert : r1170_4
|
||||
# 1170| r1170_6(String) = Call : func:r1170_3, this:r1170_1, 0:r1170_5
|
||||
# 1170| mu1170_7(unknown) = ^CallSideEffect : ~mu1169_3
|
||||
# 1170| mu1170_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1170_1
|
||||
# 1170| v1170_9(void) = ^BufferReadSideEffect[0] : &:r1170_5, ~mu1169_3
|
||||
# 1170| mu1170_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1170_5
|
||||
# 1169| r1169_4(glval<String>) = VariableAddress[#return] :
|
||||
# 1169| v1169_5(void) = ReturnValue : &:r1169_4, ~mu1169_3
|
||||
# 1169| v1169_6(void) = UnmodeledUse : mu*
|
||||
# 1169| v1169_7(void) = AliasedUse : ~mu1169_3
|
||||
# 1169| v1169_8(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
2
cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql
Normal file
2
cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql
Normal file
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IRSanity
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
@@ -0,0 +1,26 @@
|
||||
missingOperand
|
||||
| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() |
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSASanity
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
@@ -0,0 +1,2 @@
|
||||
multipleOperandMemoryLocations
|
||||
missingVirtualVariableForMemoryLocation
|
||||
@@ -852,23 +852,26 @@ ssa.cpp:
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_13
|
||||
# 199| m199_11(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_13
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_5
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_13
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_11
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_13
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_15
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
6
cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.ql
Normal file
6
cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.ql
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.PrintIR
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
1087
cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected
Normal file
1087
cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected
Normal file
File diff suppressed because it is too large
Load Diff
2
cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql
Normal file
2
cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql
Normal file
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
@@ -0,0 +1,22 @@
|
||||
missingOperand
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
@@ -0,0 +1,2 @@
|
||||
multipleOperandMemoryLocations
|
||||
missingVirtualVariableForMemoryLocation
|
||||
@@ -810,23 +810,26 @@ ssa.cpp:
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_3
|
||||
# 199| m199_11(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_3
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_3
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_5
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_3
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_11
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_3
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_13
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
6
cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.ql
Normal file
6
cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.ql
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.PrintIR
|
||||
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user