Merge remote-tracking branch 'upstream/master' into ir-crement-load

Update test output to fix semantic merge conflict.
This commit is contained in:
Jonas Jensen
2020-01-29 15:54:00 +01:00
268 changed files with 7689 additions and 966 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

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

View File

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

View File

@@ -83,10 +83,24 @@ private module VirtualDispatch {
)
or
// Flow through global variable
exists(StoreInstruction store, Variable var |
exists(StoreInstruction store |
store = src.asInstruction() and
var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and
this.flowsFromGlobal(var) and
(
exists(Variable var |
var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and
this.flowsFromGlobal(var)
)
or
exists(Variable var, FieldAccess a |
var = store
.getDestinationAddress()
.(FieldAddressInstruction)
.getObjectAddress()
.(VariableAddressInstruction)
.getASTVariable() and
this.flowsFromGlobalUnionField(var, a)
)
) and
allowFromArg = true
)
}
@@ -97,6 +111,19 @@ private module VirtualDispatch {
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var
)
}
private predicate flowsFromGlobalUnionField(Variable var, FieldAccess a) {
a.getTarget().getDeclaringType() instanceof Union and
exists(LoadInstruction load |
this.flowsFrom(DataFlow::instructionNode(load), _) and
load
.getSourceAddress()
.(FieldAddressInstruction)
.getObjectAddress()
.(VariableAddressInstruction)
.getASTVariable() = var
)
}
}
/** Call through a function pointer. */

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
/** DEPRECATED: use `hasFlow` instead. */
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
}
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
| stackVariableReachability.c:11:2:11:2 | a | ... + ... |
| stackVariableReachability.c:11:6:11:6 | a | 10 |
| stackVariableReachability.c:12:2:12:2 | a | 40 |
| stackVariableReachability.c:13:2:13:2 | a | 40 |
| stackVariableReachability.c:14:4:14:4 | a | 40 |
| stackVariableReachability.c:15:2:15:2 | a | call to f |
| stackVariableReachability.c:15:8:15:8 | a | 40 |
| stackVariableReachability.c:16:2:16:2 | a | call to f |
| stackVariableReachability.c:19:3:19:3 | b | 50 |
| stackVariableReachability.c:21:3:21:3 | b | 60 |
| stackVariableReachability.c:23:2:23:2 | c | b |
| stackVariableReachability.c:23:6:23:6 | b | 50, 60 |
| stackVariableReachability.c:24:2:24:2 | c | 50, 60, b |

View File

@@ -0,0 +1,19 @@
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
class MyStackVariableReachability extends StackVariableReachabilityWithReassignment {
MyStackVariableReachability() { this = "MyStackVariableReachability" }
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
exprDefinition(v, _, node)
}
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
node.(VariableAccess).getTarget() = v
}
override predicate isBarrier(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
}
from MyStackVariableReachability svr, ControlFlowNode sink
select sink, strictconcat(Expr source | svr.reaches(source, _, sink) | source.toString(), ", ")

View File

@@ -0,0 +1,25 @@
int cond();
int f(int x);
void test(int p)
{
int a = 10;
int b = 20;
int c = 30;
a = a + 1;
a = 40;
a++;
++a;
a = f(a);
a;
if (cond()) {
b = 50;
} else {
b = 60;
}
c = b;
c;
}

View File

@@ -0,0 +1,13 @@
| stackVariableReachability.c:11:2:11:2 | a | ... + ... |
| stackVariableReachability.c:11:6:11:6 | a | 10 |
| stackVariableReachability.c:12:2:12:2 | a | 40 |
| stackVariableReachability.c:13:2:13:2 | a | 40 |
| stackVariableReachability.c:14:4:14:4 | a | 40 |
| stackVariableReachability.c:15:2:15:2 | a | call to f |
| stackVariableReachability.c:15:8:15:8 | a | 40 |
| stackVariableReachability.c:16:2:16:2 | a | call to f |
| stackVariableReachability.c:19:3:19:3 | b | 50 |
| stackVariableReachability.c:21:3:21:3 | b | 60 |
| stackVariableReachability.c:23:2:23:2 | c | b |
| stackVariableReachability.c:23:6:23:6 | b | 50, 60 |
| stackVariableReachability.c:24:2:24:2 | c | b |

View File

@@ -0,0 +1,17 @@
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
class MyStackVariableReachability extends StackVariableReachability {
MyStackVariableReachability() { this = "MyStackVariableReachability" }
override predicate isSource(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
override predicate isSink(ControlFlowNode node, StackVariable v) {
node.(VariableAccess).getTarget() = v
}
override predicate isBarrier(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
}
from MyStackVariableReachability svr, ControlFlowNode sink
select sink, strictconcat(Expr source | svr.reaches(source, _, sink) | source.toString(), ", ")

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking
from Expr source, Element tainted
where tainted(source, tainted)
select source, tainted

View File

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

View File

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

View File

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

View File

@@ -130,3 +130,46 @@ namespace virtual_inheritance {
sink(topRef.isSource()); // flow [NOT DETECTED]
}
}
union union_with_sink_fun_ptrs {
SinkFunctionType f;
SinkFunctionType g;
} u;
void call_sink_through_union_field_f(SinkFunctionType func) {
func(source());
}
void call_sink_through_union_field_g(SinkFunctionType func) {
func(source());
}
void set_global_union_field_f() {
u.f = callSink;
}
void test_call_sink_through_union() {
set_global_union_field_f();
call_sink_through_union_field_f(u.f);
call_sink_through_union_field_g(u.g);
}
union { union_with_sink_fun_ptrs u; } u2;
void call_sink_through_union_field_u_g(SinkFunctionType func) {
func(source());
}
void call_sink_through_union_field_u_f(SinkFunctionType func) {
func(source());
}
void set_global_union_field_u_f() {
u2.u.f = callSink;
}
void test_call_sink_through_union_2() {
set_global_union_field_u_f();
call_sink_through_union_field_u_f(u2.u.f); // flow [NOT DETECTED]
call_sink_through_union_field_u_g(u2.u.g); // flow [NOT DETECTED]
}

View File

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

View File

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

View File

@@ -0,0 +1,54 @@
| test.cpp:23:23:23:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:14:23:19 | envStr | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:28 | call to getenv | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:40 | (const char *)... | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:6:25:29 | ! ... | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:12 | call to strcmp | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:29 | (bool)... | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:14:25:19 | envStr | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:6:29:28 | ! ... | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:12 | call to strcmp | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:28 | (bool)... | |
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:14:29:19 | envStr | |
| test.cpp:38:23:38:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:14:38:19 | envStr | |
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | |
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | |
| test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:28:50:40 | & ... | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | envStrGlobal |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | envStrGlobal |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:67:7:67:13 | copying | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | |
| test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | |
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | |

View File

@@ -0,0 +1,7 @@
import semmle.code.cpp.security.TaintTracking
from Expr source, Element tainted, string globalVar
where
taintedIncludingGlobalVars(source, tainted, globalVar) and
not tainted.getLocation().getFile().getExtension() = "h"
select source, tainted, globalVar

View File

@@ -0,0 +1,78 @@
// Test for the general-purpose taint-tracking
// mechanism that is used by several of the security queries.
///// Library functions //////
typedef unsigned long size_t;
int strcmp(const char *s1, const char *s2);
char *getenv(const char *name);
size_t strlen(const char *s);
char *strcpy(char *s1, const char *s2);
void *malloc(size_t size);
int atoi(const char *nptr);
//// Test code /////
bool isAdmin = false;
void test1()
{
const char *envStr = getenv("USERINFO");
if (!strcmp(envStr, "admin")) {
isAdmin = true;
}
if (!strcmp(envStr, "none")) {
isAdmin = false;
}
}
extern const char *specialUser;
void test2()
{
const char *envStr = getenv("USERINFO");
if (!strcmp(envStr, specialUser)) {
isAdmin = true;
}
}
const char *envStrGlobal;
void test3()
{
const char *envStr = getenv("USERINFO");
const char **envStr_ptr = &envStrGlobal;
*envStr_ptr = envStr;
if (!strcmp(envStrGlobal, "admin")) {
isAdmin = true;
}
}
void bugWithBinop() {
const char *userName = getenv("USER_NAME");
// The following is tainted, but should not cause
// the whole program to be considered tainted.
int bytes = strlen(userName) + 1;
}
char* copying() {
const char *userName = getenv("USER_NAME");
char copy[1024];
strcpy(copy, userName);
return copy; // copy should be tainted
}
void guard() {
int len = atoi(getenv("FOOBAZ_BRANCHING"));
if (len > 1000) return;
char **node = (char **) malloc(len * sizeof(char *));
}

View File

@@ -1,5 +1,6 @@
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.Taint
/** Common data flow configuration to be used by tests. */
class TestAllocationConfig extends TaintTracking::Configuration {
@@ -25,3 +26,39 @@ class TestAllocationConfig extends TaintTracking::Configuration {
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
}
}
class SetMemberFunction extends TaintFunction {
SetMemberFunction() { this.hasName("setMember") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isParameter(0) and
output.isQualifierObject()
}
}
class GetMemberFunction extends TaintFunction {
GetMemberFunction() { this.hasName("getMember") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and
output.isReturnValue()
}
}
class SetStringFunction extends TaintFunction {
SetStringFunction() { this.hasName("setString") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isParameterDeref(0) and
output.isQualifierObject()
}
}
class GetStringFunction extends TaintFunction {
GetStringFunction() { this.hasName("getString") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and
output.isReturnValueDeref()
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +0,0 @@
| unused_functions.c:16:13:16:27 | unused_function | Static function unused_function is unreachable | unused_functions.c:16:13:16:27 | unused_function | unused_function |
| unused_functions.c:20:13:20:28 | unused_function2 | Static function unused_function2 is unreachable ($@ must be removed at the same time) | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
| unused_functions.c:24:13:24:28 | unused_function3 | Static function unused_function3 is unreachable | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
| unused_functions.c:63:13:63:14 | h4 | Static function h4 is unreachable | unused_functions.c:63:13:63:14 | h4 | h4 |

View File

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

View File

@@ -1,2 +0,0 @@
| unused_mut.c:5:13:5:31 | mut_unused_function | Static function mut_unused_function is unreachable ($@ must be removed at the same time) | unused_mut.c:9:13:9:32 | mut_unused_function2 | mut_unused_function2 |
| unused_mut.c:9:13:9:32 | mut_unused_function2 | Static function mut_unused_function2 is unreachable ($@ must be removed at the same time) | unused_mut.c:5:13:5:31 | mut_unused_function | mut_unused_function |

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

View File

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

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

View File

@@ -0,0 +1,2 @@
multipleOperandMemoryLocations
missingVirtualVariableForMemoryLocation

View File

@@ -1166,4 +1166,8 @@ int ModeledCallTarget(int x) {
return y;
}
String ReturnObjectImpl() {
return String("foo");
}
// semmle-extractor-options: -std=c++17 --clang

View File

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

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IRSanity
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

View File

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

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSASanity
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

View File

@@ -0,0 +1,2 @@
multipleOperandMemoryLocations
missingVirtualVariableForMemoryLocation

View File

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

View File

@@ -0,0 +1,6 @@
/**
* @kind graph
*/
import semmle.code.cpp.ir.implementation.aliased_ssa.PrintIR
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

View File

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

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

View File

@@ -0,0 +1,2 @@
multipleOperandMemoryLocations
missingVirtualVariableForMemoryLocation

View File

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

View 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